blob: c554a37771b990e3aff3fc46378aaeecf6b3c252 [file] [log] [blame]
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
lrn@chromium.org1c092762011-05-09 09:42:16 +000031#include "allocation.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000032#include "list.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "log.h"
34
kasperl@chromium.org71affb52009-05-26 05:44:31 +000035namespace v8 {
36namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000038class Isolate;
39
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040// -----------------------------------------------------------------------------
41// Heap structures:
42//
43// A JS heap consists of a young generation, an old generation, and a large
44// object space. The young generation is divided into two semispaces. A
45// scavenger implements Cheney's copying algorithm. The old generation is
46// separated into a map space and an old object space. The map space contains
47// all (and only) map objects, the rest of old objects go into the old space.
48// The old generation is collected by a mark-sweep-compact collector.
49//
50// The semispaces of the young generation are contiguous. The old and map
ricow@chromium.org30ce4112010-05-31 10:38:25 +000051// spaces consists of a list of pages. A page has a page header and an object
52// area. A page size is deliberately chosen as 8K bytes.
53// The first word of a page is an opaque page header that has the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054// address of the next page and its ownership information. The second word may
ricow@chromium.org30ce4112010-05-31 10:38:25 +000055// have the allocation top address of this page. Heap objects are aligned to the
56// pointer size.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057//
58// There is a separate large object space for objects larger than
59// Page::kMaxHeapObjectSize, so that they do not have to move during
ricow@chromium.org30ce4112010-05-31 10:38:25 +000060// collection. The large object space is paged. Pages in large object space
61// may be larger than 8K.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062//
ricow@chromium.org30ce4112010-05-31 10:38:25 +000063// A card marking write barrier is used to keep track of intergenerational
64// references. Old space pages are divided into regions of Page::kRegionSize
65// size. Each region has a corresponding dirty bit in the page header which is
66// set if the region might contain pointers to new space. For details about
67// dirty bits encoding see comments in the Page::GetRegionNumberForAddress()
68// method body.
69//
70// During scavenges and mark-sweep collections we iterate intergenerational
71// pointers without decoding heap object maps so if the page belongs to old
72// pointer space or large object space it is essential to guarantee that
73// the page does not contain any garbage pointers to new space: every pointer
74// aligned word which satisfies the Heap::InNewSpace() predicate must be a
75// pointer to a live heap object in new space. Thus objects in old pointer
76// and large object spaces should have a special layout (e.g. no bare integer
77// fields). This requirement does not apply to map space which is iterated in
78// a special fashion. However we still require pointer fields of dead maps to
79// be cleaned.
80//
81// To enable lazy cleaning of old space pages we use a notion of allocation
82// watermark. Every pointer under watermark is considered to be well formed.
83// Page allocation watermark is not necessarily equal to page allocation top but
84// all alive objects on page should reside under allocation watermark.
85// During scavenge allocation watermark might be bumped and invalid pointers
86// might appear below it. To avoid following them we store a valid watermark
87// into special field in the page header and set a page WATERMARK_INVALIDATED
88// flag. For details see comments in the Page::SetAllocationWatermark() method
89// body.
90//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091
92// Some assertion macros used in the debugging mode.
93
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000094#define ASSERT_PAGE_ALIGNED(address) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095 ASSERT((OffsetFrom(address) & Page::kPageAlignmentMask) == 0)
96
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000097#define ASSERT_OBJECT_ALIGNED(address) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098 ASSERT((OffsetFrom(address) & kObjectAlignmentMask) == 0)
99
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000100#define ASSERT_MAP_ALIGNED(address) \
101 ASSERT((OffsetFrom(address) & kMapAlignmentMask) == 0)
102
103#define ASSERT_OBJECT_SIZE(size) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104 ASSERT((0 < size) && (size <= Page::kMaxHeapObjectSize))
105
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000106#define ASSERT_PAGE_OFFSET(offset) \
107 ASSERT((Page::kObjectStartOffset <= offset) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 && (offset <= Page::kPageSize))
109
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000110#define ASSERT_MAP_PAGE_INDEX(index) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111 ASSERT((0 <= index) && (index <= MapSpace::kMaxMapPageIndex))
112
113
114class PagedSpace;
115class MemoryAllocator;
kasper.lund7276f142008-07-30 08:49:36 +0000116class AllocationInfo;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117
118// -----------------------------------------------------------------------------
119// A page normally has 8K bytes. Large object pages may be larger. A page
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000120// address is always aligned to the 8K page size.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121//
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000122// Each page starts with a header of Page::kPageHeaderSize size which contains
123// bookkeeping data.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124//
125// The mark-compact collector transforms a map pointer into a page index and a
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000126// page offset. The exact encoding is described in the comments for
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000127// class MapWord in objects.h.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128//
129// The only way to get a page pointer is by calling factory methods:
130// Page* p = Page::FromAddress(addr); or
131// Page* p = Page::FromAllocationTop(top);
132class Page {
133 public:
134 // Returns the page containing a given address. The address ranges
135 // from [page_addr .. page_addr + kPageSize[
136 //
137 // Note that this function only works for addresses in normal paged
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000138 // spaces and addresses in the first 8K of large object pages (i.e.,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139 // the start of large objects but not necessarily derived pointers
140 // within them).
141 INLINE(static Page* FromAddress(Address a)) {
142 return reinterpret_cast<Page*>(OffsetFrom(a) & ~kPageAlignmentMask);
143 }
144
145 // Returns the page containing an allocation top. Because an allocation
146 // top address can be the upper bound of the page, we need to subtract
147 // it with kPointerSize first. The address ranges from
148 // [page_addr + kObjectStartOffset .. page_addr + kPageSize].
149 INLINE(static Page* FromAllocationTop(Address top)) {
150 Page* p = FromAddress(top - kPointerSize);
151 ASSERT_PAGE_OFFSET(p->Offset(top));
152 return p;
153 }
154
155 // Returns the start address of this page.
156 Address address() { return reinterpret_cast<Address>(this); }
157
158 // Checks whether this is a valid page address.
159 bool is_valid() { return address() != NULL; }
160
161 // Returns the next page of this page.
162 inline Page* next_page();
163
kasper.lund7276f142008-07-30 08:49:36 +0000164 // Return the end of allocation in this page. Undefined for unused pages.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165 inline Address AllocationTop();
166
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000167 // Return the allocation watermark for the page.
168 // For old space pages it is guaranteed that the area under the watermark
169 // does not contain any garbage pointers to new space.
170 inline Address AllocationWatermark();
171
172 // Return the allocation watermark offset from the beginning of the page.
173 inline uint32_t AllocationWatermarkOffset();
174
175 inline void SetAllocationWatermark(Address allocation_watermark);
176
177 inline void SetCachedAllocationWatermark(Address allocation_watermark);
178 inline Address CachedAllocationWatermark();
179
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180 // Returns the start address of the object area in this page.
181 Address ObjectAreaStart() { return address() + kObjectStartOffset; }
182
183 // Returns the end address (exclusive) of the object area in this page.
184 Address ObjectAreaEnd() { return address() + Page::kPageSize; }
185
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000186 // Checks whether an address is page aligned.
187 static bool IsAlignedToPageSize(Address a) {
188 return 0 == (OffsetFrom(a) & kPageAlignmentMask);
189 }
190
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000191 // True if this page was in use before current compaction started.
192 // Result is valid only for pages owned by paged spaces and
193 // only after PagedSpace::PrepareForMarkCompact was called.
194 inline bool WasInUseBeforeMC();
195
196 inline void SetWasInUseBeforeMC(bool was_in_use);
197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198 // True if this page is a large object page.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000199 inline bool IsLargeObjectPage();
200
201 inline void SetIsLargeObjectPage(bool is_large_object_page);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000202
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000203 inline bool IsPageExecutable();
204
205 inline void SetIsPageExecutable(bool is_page_executable);
206
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000207 // Returns the offset of a given address to this page.
208 INLINE(int Offset(Address a)) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000209 int offset = static_cast<int>(a - address());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210 ASSERT_PAGE_OFFSET(offset);
211 return offset;
212 }
213
214 // Returns the address for a given offset to the this page.
215 Address OffsetToAddress(int offset) {
216 ASSERT_PAGE_OFFSET(offset);
217 return address() + offset;
218 }
219
220 // ---------------------------------------------------------------------
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000221 // Card marking support
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000223 static const uint32_t kAllRegionsCleanMarks = 0x0;
224 static const uint32_t kAllRegionsDirtyMarks = 0xFFFFFFFF;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000226 inline uint32_t GetRegionMarks();
227 inline void SetRegionMarks(uint32_t dirty);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000229 inline uint32_t GetRegionMaskForAddress(Address addr);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000230 inline uint32_t GetRegionMaskForSpan(Address start, int length_in_bytes);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000231 inline int GetRegionNumberForAddress(Address addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000233 inline void MarkRegionDirty(Address addr);
234 inline bool IsRegionDirty(Address addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000236 inline void ClearRegionMarks(Address start,
237 Address end,
238 bool reaches_limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000240 // Page size in bytes. This must be a multiple of the OS page size.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241 static const int kPageSize = 1 << kPageSizeBits;
242
243 // Page size mask.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000244 static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000246 static const int kPageHeaderSize = kPointerSize + kPointerSize + kIntSize +
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 kIntSize + kPointerSize + kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000248
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000249 // The start offset of the object area in a page. Aligned to both maps and
250 // code alignment to be suitable for both.
251 static const int kObjectStartOffset =
252 CODE_POINTER_ALIGN(MAP_POINTER_ALIGN(kPageHeaderSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253
254 // Object area size in bytes.
255 static const int kObjectAreaSize = kPageSize - kObjectStartOffset;
256
257 // Maximum object size that fits in a page.
258 static const int kMaxHeapObjectSize = kObjectAreaSize;
259
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000260 static const int kDirtyFlagOffset = 2 * kPointerSize;
261 static const int kRegionSizeLog2 = 8;
262 static const int kRegionSize = 1 << kRegionSizeLog2;
263 static const intptr_t kRegionAlignmentMask = (kRegionSize - 1);
264
265 STATIC_CHECK(kRegionSize == kPageSize / kBitsPerInt);
266
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000267 enum PageFlag {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000268 IS_NORMAL_PAGE = 0,
269 WAS_IN_USE_BEFORE_MC,
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000270
271 // Page allocation watermark was bumped by preallocation during scavenge.
272 // Correct watermark can be retrieved by CachedAllocationWatermark() method
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000273 WATERMARK_INVALIDATED,
274 IS_EXECUTABLE,
275 NUM_PAGE_FLAGS // Must be last
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000276 };
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000277 static const int kPageFlagMask = (1 << NUM_PAGE_FLAGS) - 1;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000278
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000279 // To avoid an additional WATERMARK_INVALIDATED flag clearing pass during
280 // scavenge we just invalidate the watermark on each old space page after
281 // processing it. And then we flip the meaning of the WATERMARK_INVALIDATED
282 // flag at the beginning of the next scavenge and each page becomes marked as
283 // having a valid watermark.
284 //
285 // The following invariant must hold for pages in old pointer and map spaces:
286 // If page is in use then page is marked as having invalid watermark at
287 // the beginning and at the end of any GC.
288 //
289 // This invariant guarantees that after flipping flag meaning at the
290 // beginning of scavenge all pages in use will be marked as having valid
291 // watermark.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000292 static inline void FlipMeaningOfInvalidatedWatermarkFlag(Heap* heap);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000293
294 // Returns true if the page allocation watermark was not altered during
295 // scavenge.
296 inline bool IsWatermarkValid();
297
298 inline void InvalidateWatermark(bool value);
299
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000300 inline bool GetPageFlag(PageFlag flag);
301 inline void SetPageFlag(PageFlag flag, bool value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000302 inline void ClearPageFlags();
303
304 inline void ClearGCFields();
305
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000306 static const int kAllocationWatermarkOffsetShift = WATERMARK_INVALIDATED + 1;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000307 static const int kAllocationWatermarkOffsetBits = kPageSizeBits + 1;
308 static const uint32_t kAllocationWatermarkOffsetMask =
309 ((1 << kAllocationWatermarkOffsetBits) - 1) <<
310 kAllocationWatermarkOffsetShift;
311
312 static const uint32_t kFlagsMask =
313 ((1 << kAllocationWatermarkOffsetShift) - 1);
314
315 STATIC_CHECK(kBitsPerInt - kAllocationWatermarkOffsetShift >=
316 kAllocationWatermarkOffsetBits);
317
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318 //---------------------------------------------------------------------------
319 // Page header description.
320 //
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000321 // If a page is not in the large object space, the first word,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000322 // opaque_header, encodes the next page address (aligned to kPageSize 8K)
323 // and the chunk number (0 ~ 8K-1). Only MemoryAllocator should use
324 // opaque_header. The value range of the opaque_header is [0..kPageSize[,
325 // or [next_page_start, next_page_end[. It cannot point to a valid address
326 // in the current page. If a page is in the large object space, the first
327 // word *may* (if the page start and large object chunk start are the
328 // same) contain the address of the next large object chunk.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000329 intptr_t opaque_header;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330
331 // If the page is not in the large object space, the low-order bit of the
332 // second word is set. If the page is in the large object space, the
333 // second word *may* (if the page start and large object chunk start are
334 // the same) contain the large object chunk size. In either case, the
335 // low-order bit for large object pages will be cleared.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000336 // For normal pages this word is used to store page flags and
337 // offset of allocation top.
338 intptr_t flags_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000340 // This field contains dirty marks for regions covering the page. Only dirty
341 // regions might contain intergenerational references.
342 // Only 32 dirty marks are supported so for large object pages several regions
343 // might be mapped to a single dirty mark.
344 uint32_t dirty_regions_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346 // The index of the page in its owner space.
347 int mc_page_index;
348
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000349 // During mark-compact collections this field contains the forwarding address
350 // of the first live object in this page.
351 // During scavenge collection this field is used to store allocation watermark
352 // if it is altered during scavenge.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000353 Address mc_first_forwarded;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000354
355 Heap* heap_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000356};
357
358
359// ----------------------------------------------------------------------------
kasper.lund7276f142008-07-30 08:49:36 +0000360// Space is the abstract superclass for all allocation spaces.
361class Space : public Malloced {
362 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 Space(Heap* heap, AllocationSpace id, Executability executable)
364 : heap_(heap), id_(id), executable_(executable) {}
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000365
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000366 virtual ~Space() {}
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 Heap* heap() const { return heap_; }
369
kasper.lund7276f142008-07-30 08:49:36 +0000370 // Does the space need executable memory?
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000371 Executability executable() { return executable_; }
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000372
kasper.lund7276f142008-07-30 08:49:36 +0000373 // Identity used in error reporting.
374 AllocationSpace identity() { return id_; }
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000375
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000376 // Returns allocated size.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000377 virtual intptr_t Size() = 0;
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000378
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000379 // Returns size of objects. Can differ from the allocated size
380 // (e.g. see LargeObjectSpace).
381 virtual intptr_t SizeOfObjects() { return Size(); }
382
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000383#ifdef DEBUG
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000384 virtual void Print() = 0;
385#endif
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000386
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000387 // After calling this we can allocate a certain number of bytes using only
388 // linear allocation (with a LinearAllocationScope and an AlwaysAllocateScope)
389 // without using freelists or causing a GC. This is used by partial
390 // snapshots. It returns true of space was reserved or false if a GC is
391 // needed. For paged spaces the space requested must include the space wasted
392 // at the end of each when allocating linearly.
393 virtual bool ReserveSpace(int bytes) = 0;
394
kasper.lund7276f142008-07-30 08:49:36 +0000395 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 Heap* heap_;
kasper.lund7276f142008-07-30 08:49:36 +0000397 AllocationSpace id_;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000398 Executability executable_;
kasper.lund7276f142008-07-30 08:49:36 +0000399};
400
401
402// ----------------------------------------------------------------------------
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000403// All heap objects containing executable code (code objects) must be allocated
404// from a 2 GB range of memory, so that they can call each other using 32-bit
405// displacements. This happens automatically on 32-bit platforms, where 32-bit
406// displacements cover the entire 4GB virtual address space. On 64-bit
407// platforms, we support this using the CodeRange object, which reserves and
408// manages a range of virtual memory.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409class CodeRange {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000410 public:
411 // Reserves a range of virtual memory, but does not commit any of it.
412 // Can only be called once, at heap initialization time.
413 // Returns false on failure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 bool Setup(const size_t requested_size);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000415
416 // Frees the range of virtual memory, and frees the data structures used to
417 // manage it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 void TearDown();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 bool exists() { return code_range_ != NULL; }
421 bool contains(Address address) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000422 if (code_range_ == NULL) return false;
423 Address start = static_cast<Address>(code_range_->address());
424 return start <= address && address < start + code_range_->size();
425 }
426
427 // Allocates a chunk of memory from the large-object portion of
428 // the code range. On platforms with no separate code range, should
429 // not be called.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 MUST_USE_RESULT void* AllocateRawMemory(const size_t requested,
431 size_t* allocated);
432 void FreeRawMemory(void* buf, size_t length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000433
434 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 CodeRange();
436
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000437 // The reserved range of virtual memory that all code objects are put in.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000438 VirtualMemory* code_range_;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000439 // Plain old data class, just a struct plus a constructor.
440 class FreeBlock {
441 public:
442 FreeBlock(Address start_arg, size_t size_arg)
443 : start(start_arg), size(size_arg) {}
444 FreeBlock(void* start_arg, size_t size_arg)
445 : start(static_cast<Address>(start_arg)), size(size_arg) {}
446
447 Address start;
448 size_t size;
449 };
450
451 // Freed blocks of memory are added to the free list. When the allocation
452 // list is exhausted, the free list is sorted and merged to make the new
453 // allocation list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 List<FreeBlock> free_list_;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000455 // Memory is allocated from the free blocks on the allocation list.
456 // The block at current_allocation_block_index_ is the current block.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000457 List<FreeBlock> allocation_list_;
458 int current_allocation_block_index_;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000459
460 // Finds a block on the allocation list that contains at least the
461 // requested amount of memory. If none is found, sorts and merges
462 // the existing free memory blocks, and searches again.
463 // If none can be found, terminates V8 with FatalProcessOutOfMemory.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000464 void GetNextAllocationBlock(size_t requested);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000465 // Compares the start addresses of two free blocks.
466 static int CompareFreeBlockAddress(const FreeBlock* left,
467 const FreeBlock* right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468
469 friend class Isolate;
470
471 Isolate* isolate_;
472
473 DISALLOW_COPY_AND_ASSIGN(CodeRange);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000474};
475
476
477// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000478// A space acquires chunks of memory from the operating system. The memory
479// allocator manages chunks for the paged heap spaces (old space and map
480// space). A paged chunk consists of pages. Pages in a chunk have contiguous
481// addresses and are linked as a list.
482//
483// The allocator keeps an initial chunk which is used for the new space. The
484// leftover regions of the initial chunk are used for the initial chunks of
485// old space and map space if they are big enough to hold at least one page.
486// The allocator assumes that there is one old space and one map space, each
487// expands the space by allocating kPagesPerChunk pages except the last
488// expansion (before running out of space). The first chunk may contain fewer
489// than kPagesPerChunk pages as well.
490//
491// The memory allocator also allocates chunks for the large object space, but
492// they are managed by the space itself. The new space does not expand.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000493//
494// The fact that pages for paged spaces are allocated and deallocated in chunks
495// induces a constraint on the order of pages in a linked lists. We say that
496// pages are linked in the chunk-order if and only if every two consecutive
497// pages from the same chunk are consecutive in the linked list.
498//
499
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000501class MemoryAllocator {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502 public:
503 // Initializes its internal bookkeeping structures.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000504 // Max capacity of the total space and executable memory limit.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000505 bool Setup(intptr_t max_capacity, intptr_t capacity_executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000506
507 // Deletes valid chunks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000508 void TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509
510 // Reserves an initial address range of virtual memory to be split between
511 // the two new space semispaces, the old space, and the map space. The
512 // memory is not yet committed or assigned to spaces and split into pages.
513 // The initial chunk is unmapped when the memory allocator is torn down.
514 // This function should only be called when there is not already a reserved
515 // initial chunk (initial_chunk_ should be NULL). It returns the start
516 // address of the initial chunk if successful, with the side effect of
517 // setting the initial chunk, or else NULL if unsuccessful and leaves the
518 // initial chunk NULL.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 void* ReserveInitialChunk(const size_t requested);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520
521 // Commits pages from an as-yet-unmanaged block of virtual memory into a
522 // paged space. The block should be part of the initial chunk reserved via
523 // a call to ReserveInitialChunk. The number of pages is always returned in
524 // the output parameter num_pages. This function assumes that the start
525 // address is non-null and that it is big enough to hold at least one
526 // page-aligned page. The call always succeeds, and num_pages is always
527 // greater than zero.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 Page* CommitPages(Address start, size_t size, PagedSpace* owner,
529 int* num_pages);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530
531 // Commit a contiguous block of memory from the initial chunk. Assumes that
532 // the address is not NULL, the size is greater than zero, and that the
533 // block is contained in the initial chunk. Returns true if it succeeded
534 // and false otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 bool CommitBlock(Address start, size_t size, Executability executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000537 // Uncommit a contiguous block of memory [start..(start+size)[.
538 // start is not NULL, the size is greater than zero, and the
539 // block is contained in the initial chunk. Returns true if it succeeded
540 // and false otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000541 bool UncommitBlock(Address start, size_t size);
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000542
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000543 // Zaps a contiguous block of memory [start..(start+size)[ thus
544 // filling it up with a recognizable non-NULL bit pattern.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 void ZapBlock(Address start, size_t size);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547 // Attempts to allocate the requested (non-zero) number of pages from the
548 // OS. Fewer pages might be allocated than requested. If it fails to
549 // allocate memory for the OS or cannot allocate a single page, this
550 // function returns an invalid page pointer (NULL). The caller must check
551 // whether the returned page is valid (by calling Page::is_valid()). It is
552 // guaranteed that allocated pages have contiguous addresses. The actual
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000553 // number of allocated pages is returned in the output parameter
554 // allocated_pages. If the PagedSpace owner is executable and there is
555 // a code range, the pages are allocated from the code range.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Page* AllocatePages(int requested_pages, int* allocated_pages,
557 PagedSpace* owner);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000558
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000559 // Frees pages from a given page and after. Requires pages to be
560 // linked in chunk-order (see comment for class).
561 // If 'p' is the first page of a chunk, pages from 'p' are freed
562 // and this function returns an invalid page pointer.
563 // Otherwise, the function searches a page after 'p' that is
564 // the first page of a chunk. Pages after the found page
565 // are freed and the function returns 'p'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000566 Page* FreePages(Page* p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000568 // Frees all pages owned by given space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 void FreeAllPages(PagedSpace* space);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571 // Allocates and frees raw memory of certain size.
572 // These are just thin wrappers around OS::Allocate and OS::Free,
573 // but keep track of allocated bytes as part of heap.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000574 // If the flag is EXECUTABLE and a code range exists, the requested
575 // memory is allocated from the code range. If a code range exists
576 // and the freed memory is in it, the code range manages the freed memory.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 MUST_USE_RESULT void* AllocateRawMemory(const size_t requested,
578 size_t* allocated,
579 Executability executable);
580 void FreeRawMemory(void* buf,
581 size_t length,
582 Executability executable);
583 void PerformAllocationCallback(ObjectSpace space,
584 AllocationAction action,
585 size_t size);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000586
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 void AddMemoryAllocationCallback(MemoryAllocationCallback callback,
588 ObjectSpace space,
589 AllocationAction action);
590 void RemoveMemoryAllocationCallback(MemoryAllocationCallback callback);
591 bool MemoryAllocationCallbackRegistered(MemoryAllocationCallback callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592
593 // Returns the maximum available bytes of heaps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 intptr_t Available() { return capacity_ < size_ ? 0 : capacity_ - size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000596 // Returns allocated spaces in bytes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 intptr_t Size() { return size_; }
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000598
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000599 // Returns the maximum available executable bytes of heaps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 intptr_t AvailableExecutable() {
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000601 if (capacity_executable_ < size_executable_) return 0;
602 return capacity_executable_ - size_executable_;
603 }
604
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000605 // Returns allocated executable spaces in bytes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000606 intptr_t SizeExecutable() { return size_executable_; }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000607
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000608 // Returns maximum available bytes that the old space can have.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 intptr_t MaxAvailable() {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000610 return (Available() / Page::kPageSize) * Page::kObjectAreaSize;
611 }
612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000613 // Links two pages.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 inline void SetNextPage(Page* prev, Page* next);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615
616 // Returns the next page of a given page.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000617 inline Page* GetNextPage(Page* p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618
619 // Checks whether a page belongs to a space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 inline bool IsPageInSpace(Page* p, PagedSpace* space);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621
622 // Returns the space that owns the given page.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000623 inline PagedSpace* PageOwner(Page* page);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624
625 // Finds the first/last page in the same chunk as a given page.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Page* FindFirstPageInSameChunk(Page* p);
627 Page* FindLastPageInSameChunk(Page* p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000629 // Relinks list of pages owned by space to make it chunk-ordered.
630 // Returns new first and last pages of space.
631 // Also returns last page in relinked list which has WasInUsedBeforeMC
632 // flag set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000633 void RelinkPageListInChunkOrder(PagedSpace* space,
634 Page** first_page,
635 Page** last_page,
636 Page** last_page_in_use);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000637
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638#ifdef DEBUG
639 // Reports statistic info of the space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 void ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641#endif
642
643 // Due to encoding limitation, we can only have 8K chunks.
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000644 static const int kMaxNofChunks = 1 << kPageSizeBits;
ager@chromium.orga1645e22009-09-09 19:27:10 +0000645 // If a chunk has at least 16 pages, the maximum heap size is about
646 // 8K * 8K * 16 = 1G bytes.
647#ifdef V8_TARGET_ARCH_X64
648 static const int kPagesPerChunk = 32;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000649 // On 64 bit the chunk table consists of 4 levels of 4096-entry tables.
650 static const int kPagesPerChunkLog2 = 5;
651 static const int kChunkTableLevels = 4;
652 static const int kChunkTableBitsPerLevel = 12;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000653#else
ager@chromium.orga1645e22009-09-09 19:27:10 +0000654 static const int kPagesPerChunk = 16;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000655 // On 32 bit the chunk table consists of 2 levels of 256-entry tables.
656 static const int kPagesPerChunkLog2 = 4;
657 static const int kChunkTableLevels = 2;
658 static const int kChunkTableBitsPerLevel = 8;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000659#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660
661 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000662 MemoryAllocator();
663
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000664 static const int kChunkSize = kPagesPerChunk * Page::kPageSize;
665 static const int kChunkSizeLog2 = kPagesPerChunkLog2 + kPageSizeBits;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667 // Maximum space size in bytes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000668 intptr_t capacity_;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000669 // Maximum subset of capacity_ that can be executable
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000670 intptr_t capacity_executable_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000671
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672 // Allocated space size in bytes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000673 intptr_t size_;
674
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000675 // Allocated executable space size in bytes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000676 intptr_t size_executable_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000678 struct MemoryAllocationCallbackRegistration {
679 MemoryAllocationCallbackRegistration(MemoryAllocationCallback callback,
680 ObjectSpace space,
681 AllocationAction action)
682 : callback(callback), space(space), action(action) {
683 }
684 MemoryAllocationCallback callback;
685 ObjectSpace space;
686 AllocationAction action;
687 };
688 // A List of callback that are triggered when memory is allocated or free'd
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000689 List<MemoryAllocationCallbackRegistration>
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000690 memory_allocation_callbacks_;
691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000692 // The initial chunk of virtual memory.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 VirtualMemory* initial_chunk_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694
695 // Allocated chunk info: chunk start address, chunk size, and owning space.
696 class ChunkInfo BASE_EMBEDDED {
697 public:
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000698 ChunkInfo() : address_(NULL),
699 size_(0),
700 owner_(NULL),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 executable_(NOT_EXECUTABLE),
702 owner_identity_(FIRST_SPACE) {}
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000703 inline void init(Address a, size_t s, PagedSpace* o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704 Address address() { return address_; }
705 size_t size() { return size_; }
706 PagedSpace* owner() { return owner_; }
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000707 // We save executability of the owner to allow using it
708 // when collecting stats after the owner has been destroyed.
709 Executability executable() const { return executable_; }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000710 AllocationSpace owner_identity() const { return owner_identity_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711
712 private:
713 Address address_;
714 size_t size_;
715 PagedSpace* owner_;
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000716 Executability executable_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000717 AllocationSpace owner_identity_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718 };
719
720 // Chunks_, free_chunk_ids_ and top_ act as a stack of free chunk ids.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000721 List<ChunkInfo> chunks_;
722 List<int> free_chunk_ids_;
723 int max_nof_chunks_;
724 int top_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725
726 // Push/pop a free chunk id onto/from the stack.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000727 void Push(int free_chunk_id);
728 int Pop();
729 bool OutOfChunkIds() { return top_ == 0; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730
731 // Frees a chunk.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000732 void DeleteChunk(int chunk_id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000733
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000734 // Basic check whether a chunk id is in the valid range.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000735 inline bool IsValidChunkId(int chunk_id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000736
737 // Checks whether a chunk id identifies an allocated chunk.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000738 inline bool IsValidChunk(int chunk_id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739
740 // Returns the chunk id that a page belongs to.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000741 inline int GetChunkId(Page* p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000742
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000743 // True if the address lies in the initial chunk.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000744 inline bool InInitialChunk(Address address);
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000745
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000746 // Initializes pages in a chunk. Returns the first page address.
747 // This function and GetChunkId() are provided for the mark-compact
748 // collector to rebuild page headers in the from space, which is
749 // used as a marking stack and its page headers are destroyed.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000750 Page* InitializePagesInChunk(int chunk_id, int pages_in_chunk,
751 PagedSpace* owner);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000752
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000753 Page* RelinkPagesInChunk(int chunk_id,
754 Address chunk_start,
755 size_t chunk_size,
756 Page* prev,
757 Page** last_page_in_use);
758
759 friend class Isolate;
760
761 Isolate* isolate_;
762
763 DISALLOW_COPY_AND_ASSIGN(MemoryAllocator);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764};
765
766
767// -----------------------------------------------------------------------------
768// Interface for heap object iterator to be implemented by all object space
769// object iterators.
770//
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000771// NOTE: The space specific object iterators also implements the own next()
772// method which is used to avoid using virtual functions
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773// iterating a specific space.
774
775class ObjectIterator : public Malloced {
776 public:
777 virtual ~ObjectIterator() { }
778
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000779 virtual HeapObject* next_object() = 0;
780};
781
782
783// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784// Heap object iterator in new/old/map spaces.
785//
786// A HeapObjectIterator iterates objects from a given address to the
787// top of a space. The given address must be below the current
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000788// allocation pointer (space top). There are some caveats.
789//
790// (1) If the space top changes upward during iteration (because of
791// allocating new objects), the iterator does not iterate objects
792// above the original space top. The caller must create a new
793// iterator starting from the old top in order to visit these new
794// objects.
795//
796// (2) If new objects are allocated below the original allocation top
797// (e.g., free-list allocation in paged spaces), the new objects
798// may or may not be iterated depending on their position with
799// respect to the current point of iteration.
800//
801// (3) The space top should not change downward during iteration,
802// otherwise the iterator will return not-necessarily-valid
803// objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804
805class HeapObjectIterator: public ObjectIterator {
806 public:
807 // Creates a new object iterator in a given space. If a start
808 // address is not given, the iterator starts from the space bottom.
809 // If the size function is not given, the iterator calls the default
810 // Object::Size().
811 explicit HeapObjectIterator(PagedSpace* space);
812 HeapObjectIterator(PagedSpace* space, HeapObjectCallback size_func);
813 HeapObjectIterator(PagedSpace* space, Address start);
814 HeapObjectIterator(PagedSpace* space,
815 Address start,
816 HeapObjectCallback size_func);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000817 HeapObjectIterator(Page* page, HeapObjectCallback size_func);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000819 inline HeapObject* next() {
820 return (cur_addr_ < cur_limit_) ? FromCurrentPage() : FromNextPage();
821 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000822
823 // implementation of ObjectIterator.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824 virtual HeapObject* next_object() { return next(); }
825
826 private:
827 Address cur_addr_; // current iteration point
828 Address end_addr_; // end iteration point
829 Address cur_limit_; // current page limit
830 HeapObjectCallback size_func_; // size function
831 Page* end_page_; // caches the page of the end address
832
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000833 HeapObject* FromCurrentPage() {
834 ASSERT(cur_addr_ < cur_limit_);
835
836 HeapObject* obj = HeapObject::FromAddress(cur_addr_);
837 int obj_size = (size_func_ == NULL) ? obj->Size() : size_func_(obj);
838 ASSERT_OBJECT_SIZE(obj_size);
839
840 cur_addr_ += obj_size;
841 ASSERT(cur_addr_ <= cur_limit_);
842
843 return obj;
844 }
845
846 // Slow path of next, goes into the next page.
847 HeapObject* FromNextPage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000848
849 // Initializes fields.
850 void Initialize(Address start, Address end, HeapObjectCallback size_func);
851
852#ifdef DEBUG
853 // Verifies whether fields have valid values.
854 void Verify();
855#endif
856};
857
858
859// -----------------------------------------------------------------------------
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000860// A PageIterator iterates the pages in a paged space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861//
862// The PageIterator class provides three modes for iterating pages in a space:
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000863// PAGES_IN_USE iterates pages containing allocated objects.
864// PAGES_USED_BY_MC iterates pages that hold relocated objects during a
865// mark-compact collection.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866// ALL_PAGES iterates all pages in the space.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000867//
868// There are some caveats.
869//
870// (1) If the space expands during iteration, new pages will not be
871// returned by the iterator in any mode.
872//
873// (2) If new objects are allocated during iteration, they will appear
874// in pages returned by the iterator. Allocation may cause the
875// allocation pointer or MC allocation pointer in the last page to
876// change between constructing the iterator and iterating the last
877// page.
878//
879// (3) The space should not shrink during iteration, otherwise the
880// iterator will return deallocated pages.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881
882class PageIterator BASE_EMBEDDED {
883 public:
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000884 enum Mode {
885 PAGES_IN_USE,
886 PAGES_USED_BY_MC,
887 ALL_PAGES
888 };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889
890 PageIterator(PagedSpace* space, Mode mode);
891
892 inline bool has_next();
893 inline Page* next();
894
895 private:
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000896 PagedSpace* space_;
897 Page* prev_page_; // Previous page returned.
898 Page* stop_page_; // Page to stop at (last page returned by the iterator).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899};
900
901
902// -----------------------------------------------------------------------------
903// A space has a list of pages. The next page can be accessed via
904// Page::next_page() call. The next page of the last page is an
905// invalid page pointer. A space can expand and shrink dynamically.
906
907// An abstraction of allocation and relocation pointers in a page-structured
908// space.
kasper.lund7276f142008-07-30 08:49:36 +0000909class AllocationInfo {
910 public:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911 Address top; // current allocation top
912 Address limit; // current allocation limit
kasper.lund7276f142008-07-30 08:49:36 +0000913
914#ifdef DEBUG
915 bool VerifyPagedAllocation() {
916 return (Page::FromAllocationTop(top) == Page::FromAllocationTop(limit))
917 && (top <= limit);
918 }
919#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920};
921
922
923// An abstraction of the accounting statistics of a page-structured space.
924// The 'capacity' of a space is the number of object-area bytes (ie, not
925// including page bookkeeping structures) currently in the space. The 'size'
926// of a space is the number of allocated bytes, the 'waste' in the space is
927// the number of bytes that are not allocated and not available to
928// allocation without reorganizing the space via a GC (eg, small blocks due
929// to internal fragmentation, top of page areas in map space), and the bytes
930// 'available' is the number of unallocated bytes that are not waste. The
931// capacity is the sum of size, waste, and available.
932//
933// The stats are only set by functions that ensure they stay balanced. These
934// functions increase or decrease one of the non-capacity stats in
935// conjunction with capacity, or else they always balance increases and
936// decreases to the non-capacity stats.
937class AllocationStats BASE_EMBEDDED {
938 public:
939 AllocationStats() { Clear(); }
940
941 // Zero out all the allocation statistics (ie, no capacity).
942 void Clear() {
943 capacity_ = 0;
944 available_ = 0;
945 size_ = 0;
946 waste_ = 0;
947 }
948
949 // Reset the allocation statistics (ie, available = capacity with no
950 // wasted or allocated bytes).
951 void Reset() {
952 available_ = capacity_;
953 size_ = 0;
954 waste_ = 0;
955 }
956
957 // Accessors for the allocation statistics.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000958 intptr_t Capacity() { return capacity_; }
959 intptr_t Available() { return available_; }
960 intptr_t Size() { return size_; }
961 intptr_t Waste() { return waste_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962
963 // Grow the space by adding available bytes.
964 void ExpandSpace(int size_in_bytes) {
965 capacity_ += size_in_bytes;
966 available_ += size_in_bytes;
967 }
968
969 // Shrink the space by removing available bytes.
970 void ShrinkSpace(int size_in_bytes) {
971 capacity_ -= size_in_bytes;
972 available_ -= size_in_bytes;
973 }
974
975 // Allocate from available bytes (available -> size).
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000976 void AllocateBytes(intptr_t size_in_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000977 available_ -= size_in_bytes;
978 size_ += size_in_bytes;
979 }
980
981 // Free allocated bytes, making them available (size -> available).
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000982 void DeallocateBytes(intptr_t size_in_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983 size_ -= size_in_bytes;
984 available_ += size_in_bytes;
985 }
986
987 // Waste free bytes (available -> waste).
988 void WasteBytes(int size_in_bytes) {
989 available_ -= size_in_bytes;
990 waste_ += size_in_bytes;
991 }
992
993 // Consider the wasted bytes to be allocated, as they contain filler
994 // objects (waste -> size).
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000995 void FillWastedBytes(intptr_t size_in_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 waste_ -= size_in_bytes;
997 size_ += size_in_bytes;
998 }
999
1000 private:
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001001 intptr_t capacity_;
1002 intptr_t available_;
1003 intptr_t size_;
1004 intptr_t waste_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005};
1006
1007
kasper.lund7276f142008-07-30 08:49:36 +00001008class PagedSpace : public Space {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009 public:
1010 // Creates a space with a maximum capacity, and an id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 PagedSpace(Heap* heap,
1012 intptr_t max_capacity,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001013 AllocationSpace id,
1014 Executability executable);
kasper.lund7276f142008-07-30 08:49:36 +00001015
1016 virtual ~PagedSpace() {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017
1018 // Set up the space using the given address range of virtual memory (from
1019 // the memory allocator's initial chunk) if possible. If the block of
1020 // addresses is not big enough to contain a single page-aligned page, a
1021 // fresh chunk will be allocated.
1022 bool Setup(Address start, size_t size);
1023
1024 // Returns true if the space has been successfully set up and not
1025 // subsequently torn down.
1026 bool HasBeenSetup();
1027
1028 // Cleans up the space, frees all pages in this space except those belonging
1029 // to the initial chunk, uncommits addresses in the initial chunk.
1030 void TearDown();
1031
1032 // Checks whether an object/address is in this space.
1033 inline bool Contains(Address a);
1034 bool Contains(HeapObject* o) { return Contains(o->address()); }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001035 // Never crashes even if a is not a valid pointer.
1036 inline bool SafeContains(Address a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001037
kasper.lund7276f142008-07-30 08:49:36 +00001038 // Given an address occupied by a live object, return that object if it is
1039 // in this space, or Failure::Exception() if it is not. The implementation
1040 // iterates over objects in the page containing the address, the cost is
1041 // linear in the number of objects in the page. It may be slow.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001042 MUST_USE_RESULT MaybeObject* FindObject(Address addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043
kasper.lund7276f142008-07-30 08:49:36 +00001044 // Checks whether page is currently in use by this space.
1045 bool IsUsed(Page* page);
1046
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001047 void MarkAllPagesClean();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001049 // Prepares for a mark-compact GC.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001050 virtual void PrepareForMarkCompact(bool will_compact);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001051
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001052 // The top of allocation in a page in this space. Undefined if page is unused.
1053 Address PageAllocationTop(Page* page) {
1054 return page == TopPageOf(allocation_info_) ? top()
1055 : PageAllocationLimit(page);
1056 }
1057
1058 // The limit of allocation for a page in this space.
1059 virtual Address PageAllocationLimit(Page* page) = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001060
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001061 void FlushTopPageWatermark() {
1062 AllocationTopPage()->SetCachedAllocationWatermark(top());
1063 AllocationTopPage()->InvalidateWatermark(true);
1064 }
1065
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066 // Current capacity without growing (Size() + Available() + Waste()).
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001067 intptr_t Capacity() { return accounting_stats_.Capacity(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068
ager@chromium.org3811b432009-10-28 14:53:37 +00001069 // Total amount of memory committed for this space. For paged
1070 // spaces this equals the capacity.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001071 intptr_t CommittedMemory() { return Capacity(); }
ager@chromium.org3811b432009-10-28 14:53:37 +00001072
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 // Available bytes without growing.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001074 intptr_t Available() { return accounting_stats_.Available(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075
1076 // Allocated bytes in this space.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001077 virtual intptr_t Size() { return accounting_stats_.Size(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078
1079 // Wasted bytes due to fragmentation and not recoverable until the
1080 // next GC of this space.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001081 intptr_t Waste() { return accounting_stats_.Waste(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082
1083 // Returns the address of the first object in this space.
1084 Address bottom() { return first_page_->ObjectAreaStart(); }
1085
1086 // Returns the allocation pointer in this space.
1087 Address top() { return allocation_info_.top; }
1088
kasper.lund7276f142008-07-30 08:49:36 +00001089 // Allocate the requested number of bytes in the space if possible, return a
1090 // failure object if not.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001091 MUST_USE_RESULT inline MaybeObject* AllocateRaw(int size_in_bytes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092
kasper.lund7276f142008-07-30 08:49:36 +00001093 // Allocate the requested number of bytes for relocation during mark-compact
1094 // collection.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001095 MUST_USE_RESULT inline MaybeObject* MCAllocateRaw(int size_in_bytes);
kasper.lund7276f142008-07-30 08:49:36 +00001096
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097 virtual bool ReserveSpace(int bytes);
1098
1099 // Used by ReserveSpace.
1100 virtual void PutRestOfCurrentPageOnFreeList(Page* current_page) = 0;
kasper.lund7276f142008-07-30 08:49:36 +00001101
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001102 // Free all pages in range from prev (exclusive) to last (inclusive).
1103 // Freed pages are moved to the end of page list.
1104 void FreePages(Page* prev, Page* last);
1105
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001106 // Deallocates a block.
1107 virtual void DeallocateBlock(Address start,
1108 int size_in_bytes,
1109 bool add_to_freelist) = 0;
1110
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001111 // Set space allocation info.
1112 void SetTop(Address top) {
1113 allocation_info_.top = top;
1114 allocation_info_.limit = PageAllocationLimit(Page::FromAllocationTop(top));
1115 }
1116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001117 // ---------------------------------------------------------------------------
1118 // Mark-compact collection support functions
1119
1120 // Set the relocation point to the beginning of the space.
1121 void MCResetRelocationInfo();
1122
1123 // Writes relocation info to the top page.
1124 void MCWriteRelocationInfoToPage() {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001125 TopPageOf(mc_forwarding_info_)->
1126 SetAllocationWatermark(mc_forwarding_info_.top);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127 }
1128
1129 // Computes the offset of a given address in this space to the beginning
1130 // of the space.
1131 int MCSpaceOffsetForAddress(Address addr);
1132
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001133 // Updates the allocation pointer to the relocation top after a mark-compact
1134 // collection.
1135 virtual void MCCommitRelocationInfo() = 0;
1136
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 // Releases half of unused pages.
1138 void Shrink();
1139
1140 // Ensures that the capacity is at least 'capacity'. Returns false on failure.
1141 bool EnsureCapacity(int capacity);
1142
1143#ifdef DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001144 // Print meta info and objects in this space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001145 virtual void Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001147 // Verify integrity of this space.
1148 virtual void Verify(ObjectVisitor* visitor);
1149
1150 // Overridden by subclasses to verify space-specific object
1151 // properties (e.g., only maps or free-list nodes are in map space).
1152 virtual void VerifyObject(HeapObject* obj) {}
1153
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154 // Report code object related statistics
1155 void CollectCodeStatistics();
1156 static void ReportCodeStatistics();
1157 static void ResetCodeStatistics();
1158#endif
1159
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001160 // Returns the page of the allocation pointer.
1161 Page* AllocationTopPage() { return TopPageOf(allocation_info_); }
1162
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001163 void RelinkPageListInChunkOrder(bool deallocate_blocks);
1164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 protected:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 // Maximum capacity of this space.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001167 intptr_t max_capacity_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168
1169 // Accounting information for this space.
1170 AllocationStats accounting_stats_;
1171
1172 // The first page in this space.
1173 Page* first_page_;
1174
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001175 // The last page in this space. Initially set in Setup, updated in
1176 // Expand and Shrink.
1177 Page* last_page_;
1178
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001179 // True if pages owned by this space are linked in chunk-order.
1180 // See comment for class MemoryAllocator for definition of chunk-order.
1181 bool page_list_is_chunk_ordered_;
1182
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183 // Normal allocation information.
1184 AllocationInfo allocation_info_;
1185
1186 // Relocation information during mark-compact collections.
1187 AllocationInfo mc_forwarding_info_;
1188
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001189 // Bytes of each page that cannot be allocated. Possibly non-zero
1190 // for pages in spaces with only fixed-size objects. Always zero
1191 // for pages in spaces with variable sized objects (those pages are
1192 // padded with free-list nodes).
1193 int page_extra_;
1194
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195 // Sets allocation pointer to a page bottom.
1196 static void SetAllocationInfo(AllocationInfo* alloc_info, Page* p);
1197
1198 // Returns the top page specified by an allocation info structure.
1199 static Page* TopPageOf(AllocationInfo alloc_info) {
1200 return Page::FromAllocationTop(alloc_info.limit);
1201 }
1202
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00001203 int CountPagesToTop() {
1204 Page* p = Page::FromAllocationTop(allocation_info_.top);
1205 PageIterator it(this, PageIterator::ALL_PAGES);
1206 int counter = 1;
1207 while (it.has_next()) {
1208 if (it.next() == p) return counter;
1209 counter++;
1210 }
1211 UNREACHABLE();
1212 return -1;
1213 }
1214
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 // Expands the space by allocating a fixed number of pages. Returns false if
1216 // it cannot allocate requested number of pages from OS. Newly allocated
ager@chromium.org32912102009-01-16 10:38:43 +00001217 // pages are append to the last_page;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218 bool Expand(Page* last_page);
1219
kasper.lund7276f142008-07-30 08:49:36 +00001220 // Generic fast case allocation function that tries linear allocation in
1221 // the top page of 'alloc_info'. Returns NULL on failure.
1222 inline HeapObject* AllocateLinearly(AllocationInfo* alloc_info,
1223 int size_in_bytes);
1224
1225 // During normal allocation or deserialization, roll to the next page in
1226 // the space (there is assumed to be one) and allocate there. This
1227 // function is space-dependent.
1228 virtual HeapObject* AllocateInNextPage(Page* current_page,
1229 int size_in_bytes) = 0;
1230
1231 // Slow path of AllocateRaw. This function is space-dependent.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001232 MUST_USE_RESULT virtual HeapObject* SlowAllocateRaw(int size_in_bytes) = 0;
kasper.lund7276f142008-07-30 08:49:36 +00001233
1234 // Slow path of MCAllocateRaw.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001235 MUST_USE_RESULT HeapObject* SlowMCAllocateRaw(int size_in_bytes);
kasper.lund7276f142008-07-30 08:49:36 +00001236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237#ifdef DEBUG
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001238 // Returns the number of total pages in this space.
1239 int CountTotalPages();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240#endif
1241 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242
1243 // Returns a pointer to the page of the relocation pointer.
1244 Page* MCRelocationTopPage() { return TopPageOf(mc_forwarding_info_); }
1245
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00001246 friend class PageIterator;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247};
1248
1249
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001250class NumberAndSizeInfo BASE_EMBEDDED {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 public:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001252 NumberAndSizeInfo() : number_(0), bytes_(0) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001254 int number() const { return number_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 void increment_number(int num) { number_ += num; }
1256
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001257 int bytes() const { return bytes_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258 void increment_bytes(int size) { bytes_ += size; }
1259
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260 void clear() {
1261 number_ = 0;
1262 bytes_ = 0;
1263 }
1264
1265 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 int number_;
1267 int bytes_;
1268};
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001269
1270
1271// HistogramInfo class for recording a single "bar" of a histogram. This
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001272// class is used for collecting statistics to print to the log file.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001273class HistogramInfo: public NumberAndSizeInfo {
1274 public:
1275 HistogramInfo() : NumberAndSizeInfo() {}
1276
1277 const char* name() { return name_; }
1278 void set_name(const char* name) { name_ = name; }
1279
1280 private:
1281 const char* name_;
1282};
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283
1284
1285// -----------------------------------------------------------------------------
1286// SemiSpace in young generation
1287//
1288// A semispace is a contiguous chunk of memory. The mark-compact collector
1289// uses the memory in the from space as a marking stack when tracing live
1290// objects.
1291
kasper.lund7276f142008-07-30 08:49:36 +00001292class SemiSpace : public Space {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001294 // Constructor.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001295 explicit SemiSpace(Heap* heap) : Space(heap, NEW_SPACE, NOT_EXECUTABLE) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001296 start_ = NULL;
1297 age_mark_ = NULL;
1298 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299
1300 // Sets up the semispace using the given chunk.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001301 bool Setup(Address start, int initial_capacity, int maximum_capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302
1303 // Tear down the space. Heap memory was not allocated by the space, so it
1304 // is not deallocated here.
1305 void TearDown();
1306
1307 // True if the space has been set up but not torn down.
1308 bool HasBeenSetup() { return start_ != NULL; }
1309
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001310 // Grow the size of the semispace by committing extra virtual memory.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 // Assumes that the caller has checked that the semispace has not reached
ager@chromium.org32912102009-01-16 10:38:43 +00001312 // its maximum capacity (and thus there is space available in the reserved
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 // address range to grow).
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001314 bool Grow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001316 // Grow the semispace to the new capacity. The new capacity
1317 // requested must be larger than the current capacity.
1318 bool GrowTo(int new_capacity);
1319
1320 // Shrinks the semispace to the new capacity. The new capacity
1321 // requested must be more than the amount of used memory in the
1322 // semispace and less than the current capacity.
1323 bool ShrinkTo(int new_capacity);
1324
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 // Returns the start address of the space.
1326 Address low() { return start_; }
1327 // Returns one past the end address of the space.
1328 Address high() { return low() + capacity_; }
1329
1330 // Age mark accessors.
1331 Address age_mark() { return age_mark_; }
1332 void set_age_mark(Address mark) { age_mark_ = mark; }
1333
1334 // True if the address is in the address range of this semispace (not
1335 // necessarily below the allocation pointer).
1336 bool Contains(Address a) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001337 return (reinterpret_cast<uintptr_t>(a) & address_mask_)
1338 == reinterpret_cast<uintptr_t>(start_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 }
1340
1341 // True if the object is a heap object in the address range of this
1342 // semispace (not necessarily below the allocation pointer).
1343 bool Contains(Object* o) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001344 return (reinterpret_cast<uintptr_t>(o) & object_mask_) == object_expected_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 }
1346
ager@chromium.org32912102009-01-16 10:38:43 +00001347 // The offset of an address from the beginning of the space.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001348 int SpaceOffsetForAddress(Address addr) {
1349 return static_cast<int>(addr - low());
1350 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001352 // If we don't have these here then SemiSpace will be abstract. However
1353 // they should never be called.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001354 virtual intptr_t Size() {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001355 UNREACHABLE();
1356 return 0;
1357 }
1358
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001359 virtual bool ReserveSpace(int bytes) {
1360 UNREACHABLE();
1361 return false;
1362 }
1363
ager@chromium.orgadd848f2009-08-13 12:44:13 +00001364 bool is_committed() { return committed_; }
1365 bool Commit();
1366 bool Uncommit();
1367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368#ifdef DEBUG
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001369 virtual void Print();
1370 virtual void Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371#endif
1372
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001373 // Returns the current capacity of the semi space.
1374 int Capacity() { return capacity_; }
1375
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001376 // Returns the maximum capacity of the semi space.
1377 int MaximumCapacity() { return maximum_capacity_; }
1378
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001379 // Returns the initial capacity of the semi space.
1380 int InitialCapacity() { return initial_capacity_; }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001381
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382 private:
1383 // The current and maximum capacity of the space.
1384 int capacity_;
1385 int maximum_capacity_;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001386 int initial_capacity_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387
1388 // The start address of the space.
1389 Address start_;
1390 // Used to govern object promotion during mark-compact collection.
1391 Address age_mark_;
1392
1393 // Masks and comparison values to test for containment in this semispace.
ager@chromium.org5ec48922009-05-05 07:25:34 +00001394 uintptr_t address_mask_;
1395 uintptr_t object_mask_;
1396 uintptr_t object_expected_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397
ager@chromium.orgadd848f2009-08-13 12:44:13 +00001398 bool committed_;
1399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 public:
1401 TRACK_MEMORY("SemiSpace")
1402};
1403
1404
1405// A SemiSpaceIterator is an ObjectIterator that iterates over the active
1406// semispace of the heap's new space. It iterates over the objects in the
1407// semispace from a given start address (defaulting to the bottom of the
1408// semispace) to the top of the semispace. New objects allocated after the
1409// iterator is created are not iterated.
1410class SemiSpaceIterator : public ObjectIterator {
1411 public:
1412 // Create an iterator over the objects in the given space. If no start
1413 // address is given, the iterator starts from the bottom of the space. If
1414 // no size function is given, the iterator calls Object::Size().
1415 explicit SemiSpaceIterator(NewSpace* space);
1416 SemiSpaceIterator(NewSpace* space, HeapObjectCallback size_func);
1417 SemiSpaceIterator(NewSpace* space, Address start);
1418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 HeapObject* next() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001420 if (current_ == limit_) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001421
1422 HeapObject* object = HeapObject::FromAddress(current_);
1423 int size = (size_func_ == NULL) ? object->Size() : size_func_(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424
1425 current_ += size;
1426 return object;
1427 }
1428
1429 // Implementation of the ObjectIterator functions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 virtual HeapObject* next_object() { return next(); }
1431
1432 private:
1433 void Initialize(NewSpace* space, Address start, Address end,
1434 HeapObjectCallback size_func);
1435
1436 // The semispace.
1437 SemiSpace* space_;
1438 // The current iteration point.
1439 Address current_;
1440 // The end of iteration.
1441 Address limit_;
1442 // The callback function.
1443 HeapObjectCallback size_func_;
1444};
1445
1446
1447// -----------------------------------------------------------------------------
1448// The young generation space.
1449//
1450// The new space consists of a contiguous pair of semispaces. It simply
1451// forwards most functions to the appropriate semispace.
1452
kasper.lund7276f142008-07-30 08:49:36 +00001453class NewSpace : public Space {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001455 // Constructor.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001456 explicit NewSpace(Heap* heap)
1457 : Space(heap, NEW_SPACE, NOT_EXECUTABLE),
1458 to_space_(heap),
1459 from_space_(heap) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 // Sets up the new space using the given chunk.
1462 bool Setup(Address start, int size);
1463
1464 // Tears down the space. Heap memory was not allocated by the space, so it
1465 // is not deallocated here.
1466 void TearDown();
1467
1468 // True if the space has been set up but not torn down.
1469 bool HasBeenSetup() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001470 return to_space_.HasBeenSetup() && from_space_.HasBeenSetup();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 }
1472
1473 // Flip the pair of spaces.
1474 void Flip();
1475
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001476 // Grow the capacity of the semispaces. Assumes that they are not at
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001477 // their maximum capacity.
1478 void Grow();
1479
1480 // Shrink the capacity of the semispaces.
1481 void Shrink();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482
1483 // True if the address or object lies in the address range of either
1484 // semispace (not necessarily below the allocation pointer).
1485 bool Contains(Address a) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001486 return (reinterpret_cast<uintptr_t>(a) & address_mask_)
1487 == reinterpret_cast<uintptr_t>(start_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488 }
1489 bool Contains(Object* o) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001490 return (reinterpret_cast<uintptr_t>(o) & object_mask_) == object_expected_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001491 }
1492
1493 // Return the allocated bytes in the active semispace.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001494 virtual intptr_t Size() { return static_cast<int>(top() - bottom()); }
1495 // The same, but returning an int. We have to have the one that returns
1496 // intptr_t because it is inherited, but if we know we are dealing with the
1497 // new space, which can't get as big as the other spaces then this is useful:
1498 int SizeAsInt() { return static_cast<int>(Size()); }
ager@chromium.org3811b432009-10-28 14:53:37 +00001499
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 // Return the current capacity of a semispace.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001501 intptr_t Capacity() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001502 ASSERT(to_space_.Capacity() == from_space_.Capacity());
1503 return to_space_.Capacity();
1504 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001505
1506 // Return the total amount of memory committed for new space.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001507 intptr_t CommittedMemory() {
ager@chromium.org3811b432009-10-28 14:53:37 +00001508 if (from_space_.is_committed()) return 2 * Capacity();
1509 return Capacity();
1510 }
1511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001512 // Return the available bytes without growing in the active semispace.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001513 intptr_t Available() { return Capacity() - Size(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514
1515 // Return the maximum capacity of a semispace.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001516 int MaximumCapacity() {
1517 ASSERT(to_space_.MaximumCapacity() == from_space_.MaximumCapacity());
1518 return to_space_.MaximumCapacity();
1519 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001521 // Returns the initial capacity of a semispace.
1522 int InitialCapacity() {
1523 ASSERT(to_space_.InitialCapacity() == from_space_.InitialCapacity());
1524 return to_space_.InitialCapacity();
1525 }
1526
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 // Return the address of the allocation pointer in the active semispace.
1528 Address top() { return allocation_info_.top; }
1529 // Return the address of the first object in the active semispace.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001530 Address bottom() { return to_space_.low(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531
1532 // Get the age mark of the inactive semispace.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001533 Address age_mark() { return from_space_.age_mark(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // Set the age mark in the active semispace.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001535 void set_age_mark(Address mark) { to_space_.set_age_mark(mark); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536
1537 // The start address of the space and a bit mask. Anding an address in the
1538 // new space with the mask will result in the start address.
1539 Address start() { return start_; }
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001540 uintptr_t mask() { return address_mask_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001541
1542 // The allocation top and limit addresses.
1543 Address* allocation_top_address() { return &allocation_info_.top; }
1544 Address* allocation_limit_address() { return &allocation_info_.limit; }
1545
lrn@chromium.org303ada72010-10-27 09:33:13 +00001546 MUST_USE_RESULT MaybeObject* AllocateRaw(int size_in_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 return AllocateRawInternal(size_in_bytes, &allocation_info_);
1548 }
1549
1550 // Allocate the requested number of bytes for relocation during mark-compact
1551 // collection.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001552 MUST_USE_RESULT MaybeObject* MCAllocateRaw(int size_in_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553 return AllocateRawInternal(size_in_bytes, &mc_forwarding_info_);
1554 }
1555
1556 // Reset the allocation pointer to the beginning of the active semispace.
1557 void ResetAllocationInfo();
1558 // Reset the reloction pointer to the bottom of the inactive semispace in
1559 // preparation for mark-compact collection.
1560 void MCResetRelocationInfo();
1561 // Update the allocation pointer in the active semispace after a
1562 // mark-compact collection.
1563 void MCCommitRelocationInfo();
1564
1565 // Get the extent of the inactive semispace (for use as a marking stack).
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001566 Address FromSpaceLow() { return from_space_.low(); }
1567 Address FromSpaceHigh() { return from_space_.high(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568
1569 // Get the extent of the active semispace (to sweep newly copied objects
1570 // during a scavenge collection).
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001571 Address ToSpaceLow() { return to_space_.low(); }
1572 Address ToSpaceHigh() { return to_space_.high(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573
1574 // Offsets from the beginning of the semispaces.
1575 int ToSpaceOffsetForAddress(Address a) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001576 return to_space_.SpaceOffsetForAddress(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 }
1578 int FromSpaceOffsetForAddress(Address a) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001579 return from_space_.SpaceOffsetForAddress(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 }
1581
1582 // True if the object is a heap object in the address range of the
1583 // respective semispace (not necessarily below the allocation pointer of the
1584 // semispace).
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001585 bool ToSpaceContains(Object* o) { return to_space_.Contains(o); }
1586 bool FromSpaceContains(Object* o) { return from_space_.Contains(o); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001587
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001588 bool ToSpaceContains(Address a) { return to_space_.Contains(a); }
1589 bool FromSpaceContains(Address a) { return from_space_.Contains(a); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001591 virtual bool ReserveSpace(int bytes);
1592
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001593 // Resizes a sequential string which must be the most recent thing that was
1594 // allocated in new space.
1595 template <typename StringType>
1596 inline void ShrinkStringAtAllocationBoundary(String* string, int len);
1597
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598#ifdef DEBUG
1599 // Verify the active semispace.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001600 virtual void Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601 // Print the active semispace.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001602 virtual void Print() { to_space_.Print(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603#endif
1604
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605 // Iterates the active semispace to collect statistics.
1606 void CollectStatistics();
1607 // Reports previously collected statistics of the active semispace.
1608 void ReportStatistics();
1609 // Clears previously collected statistics.
1610 void ClearHistograms();
1611
1612 // Record the allocation or promotion of a heap object. Note that we don't
1613 // record every single allocation, but only those that happen in the
1614 // to space during a scavenge GC.
1615 void RecordAllocation(HeapObject* obj);
1616 void RecordPromotion(HeapObject* obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617
ager@chromium.orgadd848f2009-08-13 12:44:13 +00001618 // Return whether the operation succeded.
1619 bool CommitFromSpaceIfNeeded() {
1620 if (from_space_.is_committed()) return true;
1621 return from_space_.Commit();
1622 }
1623
1624 bool UncommitFromSpace() {
1625 if (!from_space_.is_committed()) return true;
1626 return from_space_.Uncommit();
1627 }
1628
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001630 // The semispaces.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001631 SemiSpace to_space_;
1632 SemiSpace from_space_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633
1634 // Start address and bit mask for containment testing.
1635 Address start_;
ager@chromium.org9085a012009-05-11 19:22:57 +00001636 uintptr_t address_mask_;
1637 uintptr_t object_mask_;
1638 uintptr_t object_expected_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639
1640 // Allocation pointer and limit for normal allocation and allocation during
1641 // mark-compact collection.
1642 AllocationInfo allocation_info_;
1643 AllocationInfo mc_forwarding_info_;
1644
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645 HistogramInfo* allocated_histogram_;
1646 HistogramInfo* promoted_histogram_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647
1648 // Implementation of AllocateRaw and MCAllocateRaw.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001649 MUST_USE_RESULT inline MaybeObject* AllocateRawInternal(
1650 int size_in_bytes,
1651 AllocationInfo* alloc_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652
1653 friend class SemiSpaceIterator;
1654
1655 public:
1656 TRACK_MEMORY("NewSpace")
1657};
1658
1659
1660// -----------------------------------------------------------------------------
1661// Free lists for old object spaces
1662//
1663// Free-list nodes are free blocks in the heap. They look like heap objects
1664// (free-list node pointers have the heap object tag, and they have a map like
1665// a heap object). They have a size and a next pointer. The next pointer is
1666// the raw address of the next free list node (or NULL).
1667class FreeListNode: public HeapObject {
1668 public:
1669 // Obtain a free-list node from a raw address. This is not a cast because
1670 // it does not check nor require that the first word at the address is a map
1671 // pointer.
1672 static FreeListNode* FromAddress(Address address) {
1673 return reinterpret_cast<FreeListNode*>(HeapObject::FromAddress(address));
1674 }
1675
ager@chromium.org3811b432009-10-28 14:53:37 +00001676 static inline bool IsFreeListNode(HeapObject* object);
1677
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001678 // Set the size in bytes, which can be read with HeapObject::Size(). This
1679 // function also writes a map to the first word of the block so that it
1680 // looks like a heap object to the garbage collector and heap iteration
1681 // functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001682 void set_size(Heap* heap, int size_in_bytes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683
1684 // Accessors for the next field.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001685 inline Address next(Heap* heap);
1686 inline void set_next(Heap* heap, Address next);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687
1688 private:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001689 static const int kNextOffset = POINTER_SIZE_ALIGN(ByteArray::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690
1691 DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListNode);
1692};
1693
1694
1695// The free list for the old space.
1696class OldSpaceFreeList BASE_EMBEDDED {
1697 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 OldSpaceFreeList(Heap* heap, AllocationSpace owner);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699
1700 // Clear the free list.
1701 void Reset();
1702
1703 // Return the number of bytes available on the free list.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001704 intptr_t available() { return available_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001705
1706 // Place a node on the free list. The block of size 'size_in_bytes'
1707 // starting at 'start' is placed on the free list. The return value is the
1708 // number of bytes that have been lost due to internal fragmentation by
1709 // freeing the block. Bookkeeping information will be written to the block,
1710 // ie, its contents will be destroyed. The start address should be word
1711 // aligned, and the size should be a non-zero multiple of the word size.
1712 int Free(Address start, int size_in_bytes);
1713
1714 // Allocate a block of size 'size_in_bytes' from the free list. The block
1715 // is unitialized. A failure is returned if no block is available. The
1716 // number of bytes lost to fragmentation is returned in the output parameter
1717 // 'wasted_bytes'. The size should be a non-zero multiple of the word size.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001718 MUST_USE_RESULT MaybeObject* Allocate(int size_in_bytes, int* wasted_bytes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001720 void MarkNodes();
1721
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001722 private:
1723 // The size range of blocks, in bytes. (Smaller allocations are allowed, but
1724 // will always result in waste.)
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001725 static const int kMinBlockSize = 2 * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001726 static const int kMaxBlockSize = Page::kMaxHeapObjectSize;
1727
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001728 Heap* heap_;
1729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001730 // The identity of the owning space, for building allocation Failure
1731 // objects.
1732 AllocationSpace owner_;
1733
1734 // Total available bytes in all blocks on this free list.
1735 int available_;
1736
1737 // Blocks are put on exact free lists in an array, indexed by size in words.
1738 // The available sizes are kept in an increasingly ordered list. Entries
1739 // corresponding to sizes < kMinBlockSize always have an empty free list
1740 // (but index kHead is used for the head of the size list).
1741 struct SizeNode {
1742 // Address of the head FreeListNode of the implied block size or NULL.
1743 Address head_node_;
1744 // Size (words) of the next larger available size if head_node_ != NULL.
1745 int next_size_;
1746 };
1747 static const int kFreeListsLength = kMaxBlockSize / kPointerSize + 1;
1748 SizeNode free_[kFreeListsLength];
1749
1750 // Sentinel elements for the size list. Real elements are in ]kHead..kEnd[.
1751 static const int kHead = kMinBlockSize / kPointerSize - 1;
1752 static const int kEnd = kMaxInt;
1753
1754 // We keep a "finger" in the size list to speed up a common pattern:
1755 // repeated requests for the same or increasing sizes.
1756 int finger_;
1757
1758 // Starting from *prev, find and return the smallest size >= index (words),
1759 // or kEnd. Update *prev to be the largest size < index, or kHead.
1760 int FindSize(int index, int* prev) {
1761 int cur = free_[*prev].next_size_;
1762 while (cur < index) {
1763 *prev = cur;
1764 cur = free_[cur].next_size_;
1765 }
1766 return cur;
1767 }
1768
1769 // Remove an existing element from the size list.
1770 void RemoveSize(int index) {
1771 int prev = kHead;
1772 int cur = FindSize(index, &prev);
1773 ASSERT(cur == index);
1774 free_[prev].next_size_ = free_[cur].next_size_;
1775 finger_ = prev;
1776 }
1777
1778 // Insert a new element into the size list.
1779 void InsertSize(int index) {
1780 int prev = kHead;
1781 int cur = FindSize(index, &prev);
1782 ASSERT(cur != index);
1783 free_[prev].next_size_ = index;
1784 free_[index].next_size_ = cur;
1785 }
1786
1787 // The size list is not updated during a sequence of calls to Free, but is
1788 // rebuilt before the next allocation.
1789 void RebuildSizeList();
1790 bool needs_rebuild_;
1791
kasper.lund7276f142008-07-30 08:49:36 +00001792#ifdef DEBUG
1793 // Does this free list contain a free block located at the address of 'node'?
1794 bool Contains(FreeListNode* node);
1795#endif
1796
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001797 DISALLOW_COPY_AND_ASSIGN(OldSpaceFreeList);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001798};
1799
1800
1801// The free list for the map space.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001802class FixedSizeFreeList BASE_EMBEDDED {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 FixedSizeFreeList(Heap* heap, AllocationSpace owner, int object_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001805
1806 // Clear the free list.
1807 void Reset();
1808
1809 // Return the number of bytes available on the free list.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001810 intptr_t available() { return available_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001811
1812 // Place a node on the free list. The block starting at 'start' (assumed to
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001813 // have size object_size_) is placed on the free list. Bookkeeping
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001814 // information will be written to the block, ie, its contents will be
1815 // destroyed. The start address should be word aligned.
1816 void Free(Address start);
1817
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001818 // Allocate a fixed sized block from the free list. The block is unitialized.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001819 // A failure is returned if no block is available.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001820 MUST_USE_RESULT MaybeObject* Allocate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001821
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001822 void MarkNodes();
1823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001825
1826 Heap* heap_;
1827
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001828 // Available bytes on the free list.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001829 intptr_t available_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001830
1831 // The head of the free list.
1832 Address head_;
1833
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001834 // The tail of the free list.
1835 Address tail_;
1836
kasper.lund7276f142008-07-30 08:49:36 +00001837 // The identity of the owning space, for building allocation Failure
1838 // objects.
1839 AllocationSpace owner_;
1840
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001841 // The size of the objects in this space.
1842 int object_size_;
1843
1844 DISALLOW_COPY_AND_ASSIGN(FixedSizeFreeList);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001845};
1846
1847
1848// -----------------------------------------------------------------------------
1849// Old object space (excluding map objects)
1850
1851class OldSpace : public PagedSpace {
1852 public:
1853 // Creates an old space object with a given maximum capacity.
1854 // The constructor does not allocate pages from OS.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 OldSpace(Heap* heap,
1856 intptr_t max_capacity,
1857 AllocationSpace id,
1858 Executability executable)
1859 : PagedSpace(heap, max_capacity, id, executable),
1860 free_list_(heap, id) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001861 page_extra_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001862 }
1863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001864 // The bytes available on the free list (ie, not above the linear allocation
1865 // pointer).
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001866 intptr_t AvailableFree() { return free_list_.available(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001867
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001868 // The limit of allocation for a page in this space.
1869 virtual Address PageAllocationLimit(Page* page) {
1870 return page->ObjectAreaEnd();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001871 }
1872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001873 // Give a block of memory to the space's free list. It might be added to
1874 // the free list or accounted as waste.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001875 // If add_to_freelist is false then just accounting stats are updated and
1876 // no attempt to add area to free list is made.
1877 void Free(Address start, int size_in_bytes, bool add_to_freelist) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 accounting_stats_.DeallocateBytes(size_in_bytes);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001879
1880 if (add_to_freelist) {
1881 int wasted_bytes = free_list_.Free(start, size_in_bytes);
1882 accounting_stats_.WasteBytes(wasted_bytes);
1883 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884 }
1885
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001886 virtual void DeallocateBlock(Address start,
1887 int size_in_bytes,
1888 bool add_to_freelist);
1889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 // Prepare for full garbage collection. Resets the relocation pointer and
1891 // clears the free list.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001892 virtual void PrepareForMarkCompact(bool will_compact);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001893
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001894 // Updates the allocation pointer to the relocation top after a mark-compact
1895 // collection.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001896 virtual void MCCommitRelocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001897
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001898 virtual void PutRestOfCurrentPageOnFreeList(Page* current_page);
1899
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001900 void MarkFreeListNodes() { free_list_.MarkNodes(); }
1901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001902#ifdef DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001903 // Reports statistics for the space
1904 void ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001905#endif
1906
kasper.lund7276f142008-07-30 08:49:36 +00001907 protected:
1908 // Virtual function in the superclass. Slow path of AllocateRaw.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001909 MUST_USE_RESULT HeapObject* SlowAllocateRaw(int size_in_bytes);
kasper.lund7276f142008-07-30 08:49:36 +00001910
1911 // Virtual function in the superclass. Allocate linearly at the start of
1912 // the page after current_page (there is assumed to be one).
1913 HeapObject* AllocateInNextPage(Page* current_page, int size_in_bytes);
1914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 private:
1916 // The space's free list.
1917 OldSpaceFreeList free_list_;
1918
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 public:
1920 TRACK_MEMORY("OldSpace")
1921};
1922
1923
1924// -----------------------------------------------------------------------------
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001925// Old space for objects of a fixed size
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001927class FixedSpace : public PagedSpace {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001928 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001929 FixedSpace(Heap* heap,
1930 intptr_t max_capacity,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001931 AllocationSpace id,
1932 int object_size_in_bytes,
1933 const char* name)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE),
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001935 object_size_in_bytes_(object_size_in_bytes),
1936 name_(name),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001937 free_list_(heap, id, object_size_in_bytes) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001938 page_extra_ = Page::kObjectAreaSize % object_size_in_bytes;
1939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001940
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001941 // The limit of allocation for a page in this space.
1942 virtual Address PageAllocationLimit(Page* page) {
1943 return page->ObjectAreaEnd() - page_extra_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001944 }
1945
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001946 int object_size_in_bytes() { return object_size_in_bytes_; }
1947
1948 // Give a fixed sized block of memory to the space's free list.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001949 // If add_to_freelist is false then just accounting stats are updated and
1950 // no attempt to add area to free list is made.
1951 void Free(Address start, bool add_to_freelist) {
1952 if (add_to_freelist) {
1953 free_list_.Free(start);
1954 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001955 accounting_stats_.DeallocateBytes(object_size_in_bytes_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956 }
1957
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 // Prepares for a mark-compact GC.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001959 virtual void PrepareForMarkCompact(bool will_compact);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960
1961 // Updates the allocation pointer to the relocation top after a mark-compact
1962 // collection.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001963 virtual void MCCommitRelocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001964
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001965 virtual void PutRestOfCurrentPageOnFreeList(Page* current_page);
1966
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001967 virtual void DeallocateBlock(Address start,
1968 int size_in_bytes,
1969 bool add_to_freelist);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001970
1971 void MarkFreeListNodes() { free_list_.MarkNodes(); }
1972
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973#ifdef DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001974 // Reports statistic info of the space
1975 void ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976#endif
1977
kasper.lund7276f142008-07-30 08:49:36 +00001978 protected:
1979 // Virtual function in the superclass. Slow path of AllocateRaw.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001980 MUST_USE_RESULT HeapObject* SlowAllocateRaw(int size_in_bytes);
kasper.lund7276f142008-07-30 08:49:36 +00001981
1982 // Virtual function in the superclass. Allocate linearly at the start of
1983 // the page after current_page (there is assumed to be one).
1984 HeapObject* AllocateInNextPage(Page* current_page, int size_in_bytes);
1985
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001986 void ResetFreeList() {
1987 free_list_.Reset();
1988 }
1989
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001990 private:
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001991 // The size of objects in this space.
1992 int object_size_in_bytes_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001993
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001994 // The name of this space.
1995 const char* name_;
1996
1997 // The space's free list.
1998 FixedSizeFreeList free_list_;
1999};
2000
2001
2002// -----------------------------------------------------------------------------
2003// Old space for all map objects
2004
2005class MapSpace : public FixedSpace {
2006 public:
2007 // Creates a map space object with a maximum capacity.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002008 MapSpace(Heap* heap,
2009 intptr_t max_capacity,
2010 int max_map_space_pages,
2011 AllocationSpace id)
2012 : FixedSpace(heap, max_capacity, id, Map::kSize, "map"),
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002013 max_map_space_pages_(max_map_space_pages) {
2014 ASSERT(max_map_space_pages < kMaxMapPageIndex);
2015 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002016
2017 // Prepares for a mark-compact GC.
2018 virtual void PrepareForMarkCompact(bool will_compact);
2019
2020 // Given an index, returns the page address.
2021 Address PageAddress(int page_index) { return page_addresses_[page_index]; }
2022
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002023 static const int kMaxMapPageIndex = 1 << MapWord::kMapPageIndexBits;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002024
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002025 // Are map pointers encodable into map word?
2026 bool MapPointersEncodable() {
2027 if (!FLAG_use_big_map_space) {
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002028 ASSERT(CountPagesToTop() <= kMaxMapPageIndex);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002029 return true;
2030 }
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002031 return CountPagesToTop() <= max_map_space_pages_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002032 }
2033
2034 // Should be called after forced sweep to find out if map space needs
2035 // compaction.
2036 bool NeedsCompaction(int live_maps) {
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002037 return !MapPointersEncodable() && live_maps <= CompactionThreshold();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002038 }
2039
2040 Address TopAfterCompaction(int live_maps) {
2041 ASSERT(NeedsCompaction(live_maps));
2042
2043 int pages_left = live_maps / kMapsPerPage;
2044 PageIterator it(this, PageIterator::ALL_PAGES);
2045 while (pages_left-- > 0) {
2046 ASSERT(it.has_next());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002047 it.next()->SetRegionMarks(Page::kAllRegionsCleanMarks);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002048 }
2049 ASSERT(it.has_next());
2050 Page* top_page = it.next();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002051 top_page->SetRegionMarks(Page::kAllRegionsCleanMarks);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002052 ASSERT(top_page->is_valid());
2053
2054 int offset = live_maps % kMapsPerPage * Map::kSize;
2055 Address top = top_page->ObjectAreaStart() + offset;
2056 ASSERT(top < top_page->ObjectAreaEnd());
2057 ASSERT(Contains(top));
2058
2059 return top;
2060 }
2061
2062 void FinishCompaction(Address new_top, int live_maps) {
2063 Page* top_page = Page::FromAddress(new_top);
2064 ASSERT(top_page->is_valid());
2065
2066 SetAllocationInfo(&allocation_info_, top_page);
2067 allocation_info_.top = new_top;
2068
2069 int new_size = live_maps * Map::kSize;
2070 accounting_stats_.DeallocateBytes(accounting_stats_.Size());
2071 accounting_stats_.AllocateBytes(new_size);
2072
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002073 // Flush allocation watermarks.
2074 for (Page* p = first_page_; p != top_page; p = p->next_page()) {
2075 p->SetAllocationWatermark(p->AllocationTop());
2076 }
2077 top_page->SetAllocationWatermark(new_top);
2078
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002079#ifdef DEBUG
2080 if (FLAG_enable_slow_asserts) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002081 intptr_t actual_size = 0;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002082 for (Page* p = first_page_; p != top_page; p = p->next_page())
2083 actual_size += kMapsPerPage * Map::kSize;
2084 actual_size += (new_top - top_page->ObjectAreaStart());
2085 ASSERT(accounting_stats_.Size() == actual_size);
2086 }
2087#endif
2088
2089 Shrink();
2090 ResetFreeList();
2091 }
2092
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002093 protected:
2094#ifdef DEBUG
2095 virtual void VerifyObject(HeapObject* obj);
2096#endif
2097
2098 private:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002099 static const int kMapsPerPage = Page::kObjectAreaSize / Map::kSize;
2100
2101 // Do map space compaction if there is a page gap.
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002102 int CompactionThreshold() {
2103 return kMapsPerPage * (max_map_space_pages_ - 1);
2104 }
2105
2106 const int max_map_space_pages_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002108 // An array of page start address in a map space.
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002109 Address page_addresses_[kMaxMapPageIndex];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002110
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002111 public:
2112 TRACK_MEMORY("MapSpace")
2113};
2114
2115
2116// -----------------------------------------------------------------------------
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002117// Old space for all global object property cell objects
2118
2119class CellSpace : public FixedSpace {
2120 public:
2121 // Creates a property cell space object with a maximum capacity.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002122 CellSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
2123 : FixedSpace(heap, max_capacity, id, JSGlobalPropertyCell::kSize, "cell")
2124 {}
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002125
2126 protected:
2127#ifdef DEBUG
2128 virtual void VerifyObject(HeapObject* obj);
2129#endif
2130
2131 public:
ager@chromium.org4af710e2009-09-15 12:20:11 +00002132 TRACK_MEMORY("CellSpace")
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002133};
2134
2135
2136// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137// Large objects ( > Page::kMaxHeapObjectSize ) are allocated and managed by
2138// the large object space. A large object is allocated from OS heap with
2139// extra padding bytes (Page::kPageSize + Page::kObjectStartOffset).
2140// A large object always starts at Page::kObjectStartOffset to a page.
2141// Large objects do not move during garbage collections.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002142
2143// A LargeObjectChunk holds exactly one large object page with exactly one
2144// large object.
2145class LargeObjectChunk {
2146 public:
2147 // Allocates a new LargeObjectChunk that contains a large object page
2148 // (Page::kPageSize aligned) that has at least size_in_bytes (for a large
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002149 // object) bytes after the object area start of that page.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002150 static LargeObjectChunk* New(int size_in_bytes, Executability executable);
2151
2152 // Free the memory associated with the chunk.
2153 inline void Free(Executability executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154
2155 // Interpret a raw address as a large object chunk.
2156 static LargeObjectChunk* FromAddress(Address address) {
2157 return reinterpret_cast<LargeObjectChunk*>(address);
2158 }
2159
2160 // Returns the address of this chunk.
2161 Address address() { return reinterpret_cast<Address>(this); }
2162
2163 // Accessors for the fields of the chunk.
2164 LargeObjectChunk* next() { return next_; }
2165 void set_next(LargeObjectChunk* chunk) { next_ = chunk; }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00002166 size_t size() { return size_ & ~Page::kPageFlagMask; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002167
2168 // Compute the start address in the chunk.
2169 inline Address GetStartAddress();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002170
2171 // Returns the object in this chunk.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002172 HeapObject* GetObject() { return HeapObject::FromAddress(GetStartAddress()); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002174 // Given a requested size returns the physical size of a chunk to be
2175 // allocated.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002176 static int ChunkSizeFor(int size_in_bytes);
2177
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002178 // Given a chunk size, returns the object size it can accommodate. Used by
2179 // LargeObjectSpace::Available.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002180 static intptr_t ObjectSizeFor(intptr_t chunk_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002181 if (chunk_size <= (Page::kPageSize + Page::kObjectStartOffset)) return 0;
2182 return chunk_size - Page::kPageSize - Page::kObjectStartOffset;
2183 }
2184
2185 private:
2186 // A pointer to the next large object chunk in the space or NULL.
2187 LargeObjectChunk* next_;
2188
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002189 // The total size of this chunk.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 size_t size_;
2191
2192 public:
2193 TRACK_MEMORY("LargeObjectChunk")
2194};
2195
2196
kasper.lund7276f142008-07-30 08:49:36 +00002197class LargeObjectSpace : public Space {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002198 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002199 LargeObjectSpace(Heap* heap, AllocationSpace id);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002200 virtual ~LargeObjectSpace() {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002201
2202 // Initializes internal data structures.
2203 bool Setup();
2204
2205 // Releases internal resources, frees objects in this space.
2206 void TearDown();
2207
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002208 // Allocates a (non-FixedArray, non-Code) large object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002209 MUST_USE_RESULT MaybeObject* AllocateRaw(int size_in_bytes);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002210 // Allocates a large Code object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002211 MUST_USE_RESULT MaybeObject* AllocateRawCode(int size_in_bytes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002212 // Allocates a large FixedArray.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002213 MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int size_in_bytes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002214
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002215 // Available bytes for objects in this space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002216 inline intptr_t Available();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002218 virtual intptr_t Size() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002219 return size_;
2220 }
2221
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002222 virtual intptr_t SizeOfObjects() {
2223 return objects_size_;
2224 }
2225
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002226 int PageCount() {
2227 return page_count_;
2228 }
2229
2230 // Finds an object for a given address, returns Failure::Exception()
2231 // if it is not found. The function iterates through all objects in this
2232 // space, may be slow.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002233 MaybeObject* FindObject(Address a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002234
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002235 // Finds a large object page containing the given pc, returns NULL
2236 // if such a page doesn't exist.
2237 LargeObjectChunk* FindChunkContainingPc(Address pc);
2238
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002239 // Iterates objects covered by dirty regions.
2240 void IterateDirtyRegions(ObjectSlotCallback func);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002241
2242 // Frees unmarked objects.
2243 void FreeUnmarkedObjects();
2244
2245 // Checks whether a heap object is in this space; O(1).
2246 bool Contains(HeapObject* obj);
2247
2248 // Checks whether the space is empty.
2249 bool IsEmpty() { return first_chunk_ == NULL; }
2250
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002251 // See the comments for ReserveSpace in the Space class. This has to be
2252 // called after ReserveSpace has been called on the paged spaces, since they
2253 // may use some memory, leaving less for large objects.
2254 virtual bool ReserveSpace(int bytes);
2255
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002256#ifdef DEBUG
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002257 virtual void Verify();
2258 virtual void Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002259 void ReportStatistics();
2260 void CollectCodeStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002261#endif
2262 // Checks whether an address is in the object area in this space. It
2263 // iterates all objects in the space. May be slow.
2264 bool SlowContains(Address addr) { return !FindObject(addr)->IsFailure(); }
2265
2266 private:
2267 // The head of the linked list of large object chunks.
2268 LargeObjectChunk* first_chunk_;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002269 intptr_t size_; // allocated bytes
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002270 int page_count_; // number of chunks
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002271 intptr_t objects_size_; // size of objects
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002272
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002273 // Shared implementation of AllocateRaw, AllocateRawCode and
2274 // AllocateRawFixedArray.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002275 MUST_USE_RESULT MaybeObject* AllocateRawInternal(int requested_size,
2276 int object_size,
2277 Executability executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002278
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00002279 friend class LargeObjectIterator;
2280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002281 public:
2282 TRACK_MEMORY("LargeObjectSpace")
2283};
2284
2285
2286class LargeObjectIterator: public ObjectIterator {
2287 public:
2288 explicit LargeObjectIterator(LargeObjectSpace* space);
2289 LargeObjectIterator(LargeObjectSpace* space, HeapObjectCallback size_func);
2290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002291 HeapObject* next();
2292
2293 // implementation of ObjectIterator.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002294 virtual HeapObject* next_object() { return next(); }
2295
2296 private:
2297 LargeObjectChunk* current_;
2298 HeapObjectCallback size_func_;
2299};
2300
2301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002302#ifdef DEBUG
2303struct CommentStatistic {
2304 const char* comment;
2305 int size;
2306 int count;
2307 void Clear() {
2308 comment = NULL;
2309 size = 0;
2310 count = 0;
2311 }
2312 // Must be small, since an iteration is used for lookup.
2313 static const int kMaxComments = 64;
2314};
2315#endif
2316
2317
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002318} } // namespace v8::internal
2319
2320#endif // V8_SPACES_H_