blob: 6144c95d14d689876dc2008c5c506ecfd37faa51 [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"
jkummerow@chromium.org531dfe82012-03-20 13:01:16 +000032#include "hashmap.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000033#include "list.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034#include "log.h"
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +000035#include "platform/mutex.h"
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000036#include "v8utils.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
kasperl@chromium.org71affb52009-05-26 05:44:31 +000038namespace v8 {
39namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000041class Isolate;
42
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043// -----------------------------------------------------------------------------
44// Heap structures:
45//
46// A JS heap consists of a young generation, an old generation, and a large
47// object space. The young generation is divided into two semispaces. A
48// scavenger implements Cheney's copying algorithm. The old generation is
49// separated into a map space and an old object space. The map space contains
50// all (and only) map objects, the rest of old objects go into the old space.
51// The old generation is collected by a mark-sweep-compact collector.
52//
53// The semispaces of the young generation are contiguous. The old and map
ricow@chromium.org30ce4112010-05-31 10:38:25 +000054// spaces consists of a list of pages. A page has a page header and an object
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000055// area.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056//
57// There is a separate large object space for objects larger than
58// Page::kMaxHeapObjectSize, so that they do not have to move during
ricow@chromium.org30ce4112010-05-31 10:38:25 +000059// collection. The large object space is paged. Pages in large object space
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000060// may be larger than the page size.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061//
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000062// A store-buffer based write barrier is used to keep track of intergenerational
63// references. See store-buffer.h.
ricow@chromium.org30ce4112010-05-31 10:38:25 +000064//
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000065// During scavenges and mark-sweep collections we sometimes (after a store
66// buffer overflow) iterate intergenerational pointers without decoding heap
67// object maps so if the page belongs to old pointer space or large object
68// space it is essential to guarantee that the page does not contain any
69// garbage pointers to new space: every pointer aligned word which satisfies
70// the Heap::InNewSpace() predicate must be a pointer to a live heap object in
71// new space. Thus objects in old pointer and large object spaces should have a
72// special layout (e.g. no bare integer fields). This requirement does not
73// apply to map space which is iterated in a special fashion. However we still
74// require pointer fields of dead maps to be cleaned.
ricow@chromium.org30ce4112010-05-31 10:38:25 +000075//
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000076// To enable lazy cleaning of old space pages we can mark chunks of the page
77// as being garbage. Garbage sections are marked with a special map. These
78// sections are skipped when scanning the page, even if we are otherwise
79// scanning without regard for object boundaries. Garbage sections are chained
80// together to form a free list after a GC. Garbage sections created outside
81// of GCs by object trunctation etc. may not be in the free list chain. Very
82// small free spaces are ignored, they need only be cleaned of bogus pointers
83// into new space.
ricow@chromium.org30ce4112010-05-31 10:38:25 +000084//
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000085// Each page may have up to one special garbage section. The start of this
86// section is denoted by the top field in the space. The end of the section
87// is denoted by the limit field in the space. This special garbage section
88// is not marked with a free space map in the data. The point of this section
89// is to enable linear allocation without having to constantly update the byte
90// array every time the top field is updated and a new object is created. The
91// special garbage section is not in the chain of garbage sections.
92//
93// Since the top and limit fields are in the space, not the page, only one page
94// has a special garbage section, and if the top and limit are equal then there
95// is no special garbage section.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096
97// Some assertion macros used in the debugging mode.
98
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000099#define ASSERT_PAGE_ALIGNED(address) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100 ASSERT((OffsetFrom(address) & Page::kPageAlignmentMask) == 0)
101
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000102#define ASSERT_OBJECT_ALIGNED(address) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103 ASSERT((OffsetFrom(address) & kObjectAlignmentMask) == 0)
104
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000105#define ASSERT_OBJECT_SIZE(size) \
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000106 ASSERT((0 < size) && (size <= Page::kMaxNonCodeHeapObjectSize))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000108#define ASSERT_PAGE_OFFSET(offset) \
109 ASSERT((Page::kObjectStartOffset <= offset) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 && (offset <= Page::kPageSize))
111
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000112#define ASSERT_MAP_PAGE_INDEX(index) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113 ASSERT((0 <= index) && (index <= MapSpace::kMaxMapPageIndex))
114
115
116class PagedSpace;
117class MemoryAllocator;
kasper.lund7276f142008-07-30 08:49:36 +0000118class AllocationInfo;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000119class Space;
120class FreeList;
121class MemoryChunk;
122
123class MarkBit {
124 public:
125 typedef uint32_t CellType;
126
127 inline MarkBit(CellType* cell, CellType mask, bool data_only)
128 : cell_(cell), mask_(mask), data_only_(data_only) { }
129
130 inline CellType* cell() { return cell_; }
131 inline CellType mask() { return mask_; }
132
133#ifdef DEBUG
134 bool operator==(const MarkBit& other) {
135 return cell_ == other.cell_ && mask_ == other.mask_;
136 }
137#endif
138
139 inline void Set() { *cell_ |= mask_; }
140 inline bool Get() { return (*cell_ & mask_) != 0; }
141 inline void Clear() { *cell_ &= ~mask_; }
142
143 inline bool data_only() { return data_only_; }
144
145 inline MarkBit Next() {
146 CellType new_mask = mask_ << 1;
147 if (new_mask == 0) {
148 return MarkBit(cell_ + 1, 1, data_only_);
149 } else {
150 return MarkBit(cell_, new_mask, data_only_);
151 }
152 }
153
154 private:
155 CellType* cell_;
156 CellType mask_;
157 // This boolean indicates that the object is in a data-only space with no
158 // pointers. This enables some optimizations when marking.
159 // It is expected that this field is inlined and turned into control flow
160 // at the place where the MarkBit object is created.
161 bool data_only_;
162};
163
164
165// Bitmap is a sequence of cells each containing fixed number of bits.
166class Bitmap {
167 public:
168 static const uint32_t kBitsPerCell = 32;
169 static const uint32_t kBitsPerCellLog2 = 5;
170 static const uint32_t kBitIndexMask = kBitsPerCell - 1;
171 static const uint32_t kBytesPerCell = kBitsPerCell / kBitsPerByte;
172 static const uint32_t kBytesPerCellLog2 = kBitsPerCellLog2 - kBitsPerByteLog2;
173
174 static const size_t kLength =
175 (1 << kPageSizeBits) >> (kPointerSizeLog2);
176
177 static const size_t kSize =
178 (1 << kPageSizeBits) >> (kPointerSizeLog2 + kBitsPerByteLog2);
179
180
181 static int CellsForLength(int length) {
182 return (length + kBitsPerCell - 1) >> kBitsPerCellLog2;
183 }
184
185 int CellsCount() {
186 return CellsForLength(kLength);
187 }
188
189 static int SizeFor(int cells_count) {
190 return sizeof(MarkBit::CellType) * cells_count;
191 }
192
193 INLINE(static uint32_t IndexToCell(uint32_t index)) {
194 return index >> kBitsPerCellLog2;
195 }
196
197 INLINE(static uint32_t CellToIndex(uint32_t index)) {
198 return index << kBitsPerCellLog2;
199 }
200
201 INLINE(static uint32_t CellAlignIndex(uint32_t index)) {
202 return (index + kBitIndexMask) & ~kBitIndexMask;
203 }
204
205 INLINE(MarkBit::CellType* cells()) {
206 return reinterpret_cast<MarkBit::CellType*>(this);
207 }
208
209 INLINE(Address address()) {
210 return reinterpret_cast<Address>(this);
211 }
212
213 INLINE(static Bitmap* FromAddress(Address addr)) {
214 return reinterpret_cast<Bitmap*>(addr);
215 }
216
217 inline MarkBit MarkBitFromIndex(uint32_t index, bool data_only = false) {
218 MarkBit::CellType mask = 1 << (index & kBitIndexMask);
219 MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2);
220 return MarkBit(cell, mask, data_only);
221 }
222
223 static inline void Clear(MemoryChunk* chunk);
224
225 static void PrintWord(uint32_t word, uint32_t himask = 0) {
226 for (uint32_t mask = 1; mask != 0; mask <<= 1) {
227 if ((mask & himask) != 0) PrintF("[");
228 PrintF((mask & word) ? "1" : "0");
229 if ((mask & himask) != 0) PrintF("]");
230 }
231 }
232
233 class CellPrinter {
234 public:
235 CellPrinter() : seq_start(0), seq_type(0), seq_length(0) { }
236
237 void Print(uint32_t pos, uint32_t cell) {
238 if (cell == seq_type) {
239 seq_length++;
240 return;
241 }
242
243 Flush();
244
245 if (IsSeq(cell)) {
246 seq_start = pos;
247 seq_length = 0;
248 seq_type = cell;
249 return;
250 }
251
252 PrintF("%d: ", pos);
253 PrintWord(cell);
254 PrintF("\n");
255 }
256
257 void Flush() {
258 if (seq_length > 0) {
259 PrintF("%d: %dx%d\n",
260 seq_start,
261 seq_type == 0 ? 0 : 1,
262 seq_length * kBitsPerCell);
263 seq_length = 0;
264 }
265 }
266
267 static bool IsSeq(uint32_t cell) { return cell == 0 || cell == 0xFFFFFFFF; }
268
269 private:
270 uint32_t seq_start;
271 uint32_t seq_type;
272 uint32_t seq_length;
273 };
274
275 void Print() {
276 CellPrinter printer;
277 for (int i = 0; i < CellsCount(); i++) {
278 printer.Print(i, cells()[i]);
279 }
280 printer.Flush();
281 PrintF("\n");
282 }
283
284 bool IsClean() {
285 for (int i = 0; i < CellsCount(); i++) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000286 if (cells()[i] != 0) {
287 return false;
288 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000289 }
290 return true;
291 }
292};
293
294
295class SkipList;
296class SlotsBuffer;
297
298// MemoryChunk represents a memory region owned by a specific space.
299// It is divided into the header and the body. Chunk start is always
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000300// 1MB aligned. Start of the body is aligned so it can accommodate
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000301// any heap object.
302class MemoryChunk {
303 public:
304 // Only works if the pointer is in the first kPageSize of the MemoryChunk.
305 static MemoryChunk* FromAddress(Address a) {
306 return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask);
307 }
308
309 // Only works for addresses in pointer spaces, not data or code spaces.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000310 static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000311
312 Address address() { return reinterpret_cast<Address>(this); }
313
314 bool is_valid() { return address() != NULL; }
315
316 MemoryChunk* next_chunk() const { return next_chunk_; }
317 MemoryChunk* prev_chunk() const { return prev_chunk_; }
318
319 void set_next_chunk(MemoryChunk* next) { next_chunk_ = next; }
320 void set_prev_chunk(MemoryChunk* prev) { prev_chunk_ = prev; }
321
322 Space* owner() const {
323 if ((reinterpret_cast<intptr_t>(owner_) & kFailureTagMask) ==
324 kFailureTag) {
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000325 return reinterpret_cast<Space*>(reinterpret_cast<intptr_t>(owner_) -
326 kFailureTag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000327 } else {
328 return NULL;
329 }
330 }
331
332 void set_owner(Space* space) {
333 ASSERT((reinterpret_cast<intptr_t>(space) & kFailureTagMask) == 0);
334 owner_ = reinterpret_cast<Address>(space) + kFailureTag;
335 ASSERT((reinterpret_cast<intptr_t>(owner_) & kFailureTagMask) ==
336 kFailureTag);
337 }
338
339 VirtualMemory* reserved_memory() {
340 return &reservation_;
341 }
342
343 void InitializeReservedMemory() {
344 reservation_.Reset();
345 }
346
347 void set_reserved_memory(VirtualMemory* reservation) {
348 ASSERT_NOT_NULL(reservation);
349 reservation_.TakeControl(reservation);
350 }
351
352 bool scan_on_scavenge() { return IsFlagSet(SCAN_ON_SCAVENGE); }
353 void initialize_scan_on_scavenge(bool scan) {
354 if (scan) {
355 SetFlag(SCAN_ON_SCAVENGE);
356 } else {
357 ClearFlag(SCAN_ON_SCAVENGE);
358 }
359 }
360 inline void set_scan_on_scavenge(bool scan);
361
362 int store_buffer_counter() { return store_buffer_counter_; }
363 void set_store_buffer_counter(int counter) {
364 store_buffer_counter_ = counter;
365 }
366
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000367 bool Contains(Address addr) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000368 return addr >= area_start() && addr < area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000369 }
370
371 // Checks whether addr can be a limit of addresses in this page.
372 // It's a limit if it's in the page, or if it's just after the
373 // last byte of the page.
374 bool ContainsLimit(Address addr) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000375 return addr >= area_start() && addr <= area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000376 }
377
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000378 // Every n write barrier invocations we go to runtime even though
379 // we could have handled it in generated code. This lets us check
380 // whether we have hit the limit and should do some more marking.
381 static const int kWriteBarrierCounterGranularity = 500;
382
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000383 enum MemoryChunkFlags {
384 IS_EXECUTABLE,
385 ABOUT_TO_BE_FREED,
386 POINTERS_TO_HERE_ARE_INTERESTING,
387 POINTERS_FROM_HERE_ARE_INTERESTING,
388 SCAN_ON_SCAVENGE,
389 IN_FROM_SPACE, // Mutually exclusive with IN_TO_SPACE.
390 IN_TO_SPACE, // All pages in new space has one of these two set.
391 NEW_SPACE_BELOW_AGE_MARK,
392 CONTAINS_ONLY_DATA,
393 EVACUATION_CANDIDATE,
394 RESCAN_ON_EVACUATION,
395
396 // Pages swept precisely can be iterated, hitting only the live objects.
397 // Whereas those swept conservatively cannot be iterated over. Both flags
398 // indicate that marking bits have been cleared by the sweeper, otherwise
399 // marking bits are still intact.
400 WAS_SWEPT_PRECISELY,
401 WAS_SWEPT_CONSERVATIVELY,
402
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000403 // Large objects can have a progress bar in their page header. These object
404 // are scanned in increments and will be kept black while being scanned.
405 // Even if the mutator writes to them they will be kept black and a white
406 // to grey transition is performed in the value.
407 HAS_PROGRESS_BAR,
408
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000409 // Last flag, keep at bottom.
410 NUM_MEMORY_CHUNK_FLAGS
411 };
412
413
414 static const int kPointersToHereAreInterestingMask =
415 1 << POINTERS_TO_HERE_ARE_INTERESTING;
416
417 static const int kPointersFromHereAreInterestingMask =
418 1 << POINTERS_FROM_HERE_ARE_INTERESTING;
419
420 static const int kEvacuationCandidateMask =
421 1 << EVACUATION_CANDIDATE;
422
423 static const int kSkipEvacuationSlotsRecordingMask =
424 (1 << EVACUATION_CANDIDATE) |
425 (1 << RESCAN_ON_EVACUATION) |
426 (1 << IN_FROM_SPACE) |
427 (1 << IN_TO_SPACE);
428
429
430 void SetFlag(int flag) {
431 flags_ |= static_cast<uintptr_t>(1) << flag;
432 }
433
434 void ClearFlag(int flag) {
435 flags_ &= ~(static_cast<uintptr_t>(1) << flag);
436 }
437
438 void SetFlagTo(int flag, bool value) {
439 if (value) {
440 SetFlag(flag);
441 } else {
442 ClearFlag(flag);
443 }
444 }
445
446 bool IsFlagSet(int flag) {
447 return (flags_ & (static_cast<uintptr_t>(1) << flag)) != 0;
448 }
449
450 // Set or clear multiple flags at a time. The flags in the mask
451 // are set to the value in "flags", the rest retain the current value
452 // in flags_.
453 void SetFlags(intptr_t flags, intptr_t mask) {
454 flags_ = (flags_ & ~mask) | (flags & mask);
455 }
456
457 // Return all current flags.
458 intptr_t GetFlags() { return flags_; }
459
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000460 intptr_t parallel_sweeping() const {
461 return parallel_sweeping_;
462 }
463
464 void set_parallel_sweeping(intptr_t state) {
465 parallel_sweeping_ = state;
466 }
467
468 bool TryParallelSweeping() {
469 return NoBarrier_CompareAndSwap(&parallel_sweeping_, 1, 0) == 1;
470 }
471
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000472 // Manage live byte count (count of bytes known to be live,
473 // because they are marked black).
474 void ResetLiveBytes() {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000475 if (FLAG_gc_verbose) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000476 PrintF("ResetLiveBytes:%p:%x->0\n",
477 static_cast<void*>(this), live_byte_count_);
478 }
479 live_byte_count_ = 0;
480 }
481 void IncrementLiveBytes(int by) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000482 if (FLAG_gc_verbose) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000483 printf("UpdateLiveBytes:%p:%x%c=%x->%x\n",
484 static_cast<void*>(this), live_byte_count_,
485 ((by < 0) ? '-' : '+'), ((by < 0) ? -by : by),
486 live_byte_count_ + by);
487 }
488 live_byte_count_ += by;
489 ASSERT_LE(static_cast<unsigned>(live_byte_count_), size_);
490 }
491 int LiveBytes() {
492 ASSERT(static_cast<unsigned>(live_byte_count_) <= size_);
493 return live_byte_count_;
494 }
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000495
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000496 int write_barrier_counter() {
497 return static_cast<int>(write_barrier_counter_);
498 }
499
500 void set_write_barrier_counter(int counter) {
501 write_barrier_counter_ = counter;
502 }
503
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000504 int progress_bar() {
505 ASSERT(IsFlagSet(HAS_PROGRESS_BAR));
506 return progress_bar_;
507 }
508
509 void set_progress_bar(int progress_bar) {
510 ASSERT(IsFlagSet(HAS_PROGRESS_BAR));
511 progress_bar_ = progress_bar;
512 }
513
514 void ResetProgressBar() {
515 if (IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) {
516 set_progress_bar(0);
517 ClearFlag(MemoryChunk::HAS_PROGRESS_BAR);
518 }
519 }
520
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000521 bool IsLeftOfProgressBar(Object** slot) {
522 Address slot_address = reinterpret_cast<Address>(slot);
523 ASSERT(slot_address > this->address());
524 return (slot_address - (this->address() + kObjectStartOffset)) <
525 progress_bar();
526 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000527
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000528 static void IncrementLiveBytesFromGC(Address address, int by) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000529 MemoryChunk::FromAddress(address)->IncrementLiveBytes(by);
530 }
531
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000532 static void IncrementLiveBytesFromMutator(Address address, int by);
533
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000534 static const intptr_t kAlignment =
535 (static_cast<uintptr_t>(1) << kPageSizeBits);
536
537 static const intptr_t kAlignmentMask = kAlignment - 1;
538
539 static const intptr_t kSizeOffset = kPointerSize + kPointerSize;
540
541 static const intptr_t kLiveBytesOffset =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000542 kSizeOffset + kPointerSize + kPointerSize + kPointerSize +
543 kPointerSize + kPointerSize +
544 kPointerSize + kPointerSize + kPointerSize + kIntSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000545
546 static const size_t kSlotsBufferOffset = kLiveBytesOffset + kIntSize;
547
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000548 static const size_t kWriteBarrierCounterOffset =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000549 kSlotsBufferOffset + kPointerSize + kPointerSize;
550
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000551 static const size_t kHeaderSize = kWriteBarrierCounterOffset + kPointerSize +
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000552 kIntSize + kIntSize + kPointerSize +
553 5 * kPointerSize;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000554
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000555 static const int kBodyOffset =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000556 CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000557
558 // The start offset of the object area in a page. Aligned to both maps and
559 // code alignment to be suitable for both. Also aligned to 32 words because
560 // the marking bitmap is arranged in 32 bit chunks.
561 static const int kObjectStartAlignment = 32 * kPointerSize;
562 static const int kObjectStartOffset = kBodyOffset - 1 +
563 (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment);
564
565 size_t size() const { return size_; }
566
danno@chromium.org2c456792011-11-11 12:00:53 +0000567 void set_size(size_t size) {
568 size_ = size;
569 }
570
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000571 void SetArea(Address area_start, Address area_end) {
572 area_start_ = area_start;
573 area_end_ = area_end;
574 }
575
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000576 Executability executable() {
577 return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE;
578 }
579
580 bool ContainsOnlyData() {
581 return IsFlagSet(CONTAINS_ONLY_DATA);
582 }
583
584 bool InNewSpace() {
585 return (flags_ & ((1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE))) != 0;
586 }
587
588 bool InToSpace() {
589 return IsFlagSet(IN_TO_SPACE);
590 }
591
592 bool InFromSpace() {
593 return IsFlagSet(IN_FROM_SPACE);
594 }
595
596 // ---------------------------------------------------------------------
597 // Markbits support
598
599 inline Bitmap* markbits() {
600 return Bitmap::FromAddress(address() + kHeaderSize);
601 }
602
603 void PrintMarkbits() { markbits()->Print(); }
604
605 inline uint32_t AddressToMarkbitIndex(Address addr) {
606 return static_cast<uint32_t>(addr - this->address()) >> kPointerSizeLog2;
607 }
608
609 inline static uint32_t FastAddressToMarkbitIndex(Address addr) {
610 const intptr_t offset =
611 reinterpret_cast<intptr_t>(addr) & kAlignmentMask;
612
613 return static_cast<uint32_t>(offset) >> kPointerSizeLog2;
614 }
615
616 inline Address MarkbitIndexToAddress(uint32_t index) {
617 return this->address() + (index << kPointerSizeLog2);
618 }
619
620 void InsertAfter(MemoryChunk* other);
621 void Unlink();
622
623 inline Heap* heap() { return heap_; }
624
625 static const int kFlagsOffset = kPointerSize * 3;
626
627 bool IsEvacuationCandidate() { return IsFlagSet(EVACUATION_CANDIDATE); }
628
629 bool ShouldSkipEvacuationSlotRecording() {
630 return (flags_ & kSkipEvacuationSlotsRecordingMask) != 0;
631 }
632
633 inline SkipList* skip_list() {
634 return skip_list_;
635 }
636
637 inline void set_skip_list(SkipList* skip_list) {
638 skip_list_ = skip_list;
639 }
640
641 inline SlotsBuffer* slots_buffer() {
642 return slots_buffer_;
643 }
644
645 inline SlotsBuffer** slots_buffer_address() {
646 return &slots_buffer_;
647 }
648
649 void MarkEvacuationCandidate() {
650 ASSERT(slots_buffer_ == NULL);
651 SetFlag(EVACUATION_CANDIDATE);
652 }
653
654 void ClearEvacuationCandidate() {
655 ASSERT(slots_buffer_ == NULL);
656 ClearFlag(EVACUATION_CANDIDATE);
657 }
658
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000659 Address area_start() { return area_start_; }
660 Address area_end() { return area_end_; }
661 int area_size() {
662 return static_cast<int>(area_end() - area_start());
663 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000664 bool CommitArea(size_t requested);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000665
danno@chromium.org72204d52012-10-31 10:02:10 +0000666 // Approximate amount of physical memory committed for this chunk.
667 size_t CommittedPhysicalMemory() {
668 return high_water_mark_;
669 }
670
671 static inline void UpdateHighWaterMark(Address mark);
672
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000673 protected:
674 MemoryChunk* next_chunk_;
675 MemoryChunk* prev_chunk_;
676 size_t size_;
677 intptr_t flags_;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000678
679 // Start and end of allocatable memory on this chunk.
680 Address area_start_;
681 Address area_end_;
682
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000683 // If the chunk needs to remember its memory reservation, it is stored here.
684 VirtualMemory reservation_;
685 // The identity of the owning space. This is tagged as a failure pointer, but
686 // no failure can be in an object, so this can be distinguished from any entry
687 // in a fixed array.
688 Address owner_;
689 Heap* heap_;
690 // Used by the store buffer to keep track of which pages to mark scan-on-
691 // scavenge.
692 int store_buffer_counter_;
693 // Count of bytes marked black on page.
694 int live_byte_count_;
695 SlotsBuffer* slots_buffer_;
696 SkipList* skip_list_;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000697 intptr_t write_barrier_counter_;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000698 // Used by the incremental marker to keep track of the scanning progress in
699 // large objects that have a progress bar and are scanned in increments.
700 int progress_bar_;
danno@chromium.org72204d52012-10-31 10:02:10 +0000701 // Assuming the initial allocation on a page is sequential,
702 // count highest number of bytes ever allocated on the page.
703 int high_water_mark_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000704
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000705 intptr_t parallel_sweeping_;
706
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000707 // PagedSpace free-list statistics.
708 intptr_t available_in_small_free_list_;
709 intptr_t available_in_medium_free_list_;
710 intptr_t available_in_large_free_list_;
711 intptr_t available_in_huge_free_list_;
712 intptr_t non_available_small_blocks_;
713
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000714 static MemoryChunk* Initialize(Heap* heap,
715 Address base,
716 size_t size,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000717 Address area_start,
718 Address area_end,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000719 Executability executable,
720 Space* owner);
721
722 friend class MemoryAllocator;
723};
724
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000725
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000726STATIC_CHECK(sizeof(MemoryChunk) <= MemoryChunk::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000727
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000728
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000729// -----------------------------------------------------------------------------
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000730// A page is a memory chunk of a size 1MB. Large object pages may be larger.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000731//
732// The only way to get a page pointer is by calling factory methods:
733// Page* p = Page::FromAddress(addr); or
734// Page* p = Page::FromAllocationTop(top);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000735class Page : public MemoryChunk {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000736 public:
737 // Returns the page containing a given address. The address ranges
738 // from [page_addr .. page_addr + kPageSize[
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000739 // This only works if the object is in fact in a page. See also MemoryChunk::
740 // FromAddress() and FromAnyAddress().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741 INLINE(static Page* FromAddress(Address a)) {
742 return reinterpret_cast<Page*>(OffsetFrom(a) & ~kPageAlignmentMask);
743 }
744
745 // Returns the page containing an allocation top. Because an allocation
746 // top address can be the upper bound of the page, we need to subtract
747 // it with kPointerSize first. The address ranges from
748 // [page_addr + kObjectStartOffset .. page_addr + kPageSize].
749 INLINE(static Page* FromAllocationTop(Address top)) {
750 Page* p = FromAddress(top - kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751 return p;
752 }
753
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000754 // Returns the next page in the chain of pages owned by a space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000755 inline Page* next_page();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000756 inline Page* prev_page();
757 inline void set_next_page(Page* page);
758 inline void set_prev_page(Page* page);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000759
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760 // Checks whether an address is page aligned.
761 static bool IsAlignedToPageSize(Address a) {
762 return 0 == (OffsetFrom(a) & kPageAlignmentMask);
763 }
764
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765 // Returns the offset of a given address to this page.
766 INLINE(int Offset(Address a)) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000767 int offset = static_cast<int>(a - address());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000768 return offset;
769 }
770
771 // Returns the address for a given offset to the this page.
772 Address OffsetToAddress(int offset) {
773 ASSERT_PAGE_OFFSET(offset);
774 return address() + offset;
775 }
776
777 // ---------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000779 // Page size in bytes. This must be a multiple of the OS page size.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780 static const int kPageSize = 1 << kPageSizeBits;
781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782 // Object area size in bytes.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000783 static const int kNonCodeObjectAreaSize = kPageSize - kObjectStartOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784
hpayer@chromium.org83fa61b2013-07-24 09:36:58 +0000785 // Maximum object size that fits in a page. Objects larger than that size
786 // are allocated in large object space and are never moved in memory. This
787 // also applies to new space allocation, since objects are never migrated
danno@chromium.org59400602013-08-13 17:09:37 +0000788 // from new space to large object space. Takes double alignment into account.
789 static const int kMaxNonCodeHeapObjectSize =
790 kNonCodeObjectAreaSize - kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000792 // Page size mask.
793 static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000794
795 inline void ClearGCFields();
796
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000797 static inline Page* Initialize(Heap* heap,
798 MemoryChunk* chunk,
799 Executability executable,
800 PagedSpace* owner);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000801
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000802 void InitializeAsAnchor(PagedSpace* owner);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000803
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000804 bool WasSweptPrecisely() { return IsFlagSet(WAS_SWEPT_PRECISELY); }
805 bool WasSweptConservatively() { return IsFlagSet(WAS_SWEPT_CONSERVATIVELY); }
806 bool WasSwept() { return WasSweptPrecisely() || WasSweptConservatively(); }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000807
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000808 void MarkSweptPrecisely() { SetFlag(WAS_SWEPT_PRECISELY); }
809 void MarkSweptConservatively() { SetFlag(WAS_SWEPT_CONSERVATIVELY); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000810
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000811 void ClearSweptPrecisely() { ClearFlag(WAS_SWEPT_PRECISELY); }
812 void ClearSweptConservatively() { ClearFlag(WAS_SWEPT_CONSERVATIVELY); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000814 void ResetFreeListStatistics();
815
816#define FRAGMENTATION_STATS_ACCESSORS(type, name) \
817 type name() { return name##_; } \
818 void set_##name(type name) { name##_ = name; } \
819 void add_##name(type name) { name##_ += name; }
820
821 FRAGMENTATION_STATS_ACCESSORS(intptr_t, non_available_small_blocks)
822 FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_small_free_list)
823 FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_medium_free_list)
824 FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_large_free_list)
825 FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_huge_free_list)
826
827#undef FRAGMENTATION_STATS_ACCESSORS
828
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000829#ifdef DEBUG
830 void Print();
831#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 friend class MemoryAllocator;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000834};
835
836
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000837STATIC_CHECK(sizeof(Page) <= MemoryChunk::kHeaderSize);
838
839
840class LargePage : public MemoryChunk {
841 public:
842 HeapObject* GetObject() {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000843 return HeapObject::FromAddress(area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000844 }
845
846 inline LargePage* next_page() const {
847 return static_cast<LargePage*>(next_chunk());
848 }
849
850 inline void set_next_page(LargePage* page) {
851 set_next_chunk(page);
852 }
853 private:
854 static inline LargePage* Initialize(Heap* heap, MemoryChunk* chunk);
855
856 friend class MemoryAllocator;
857};
858
859STATIC_CHECK(sizeof(LargePage) <= MemoryChunk::kHeaderSize);
860
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861// ----------------------------------------------------------------------------
kasper.lund7276f142008-07-30 08:49:36 +0000862// Space is the abstract superclass for all allocation spaces.
863class Space : public Malloced {
864 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 Space(Heap* heap, AllocationSpace id, Executability executable)
866 : heap_(heap), id_(id), executable_(executable) {}
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000867
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000868 virtual ~Space() {}
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000870 Heap* heap() const { return heap_; }
871
kasper.lund7276f142008-07-30 08:49:36 +0000872 // Does the space need executable memory?
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000873 Executability executable() { return executable_; }
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000874
kasper.lund7276f142008-07-30 08:49:36 +0000875 // Identity used in error reporting.
876 AllocationSpace identity() { return id_; }
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000877
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000878 // Returns allocated size.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000879 virtual intptr_t Size() = 0;
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000880
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000881 // Returns size of objects. Can differ from the allocated size
882 // (e.g. see LargeObjectSpace).
883 virtual intptr_t SizeOfObjects() { return Size(); }
884
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000885 virtual int RoundSizeDownToObjectAlignment(int size) {
886 if (id_ == CODE_SPACE) {
887 return RoundDown(size, kCodeAlignment);
888 } else {
889 return RoundDown(size, kPointerSize);
890 }
891 }
892
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000893#ifdef DEBUG
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000894 virtual void Print() = 0;
895#endif
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000896
kasper.lund7276f142008-07-30 08:49:36 +0000897 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000898 Heap* heap_;
kasper.lund7276f142008-07-30 08:49:36 +0000899 AllocationSpace id_;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000900 Executability executable_;
kasper.lund7276f142008-07-30 08:49:36 +0000901};
902
903
904// ----------------------------------------------------------------------------
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000905// All heap objects containing executable code (code objects) must be allocated
906// from a 2 GB range of memory, so that they can call each other using 32-bit
907// displacements. This happens automatically on 32-bit platforms, where 32-bit
908// displacements cover the entire 4GB virtual address space. On 64-bit
909// platforms, we support this using the CodeRange object, which reserves and
910// manages a range of virtual memory.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000911class CodeRange {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000912 public:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000913 explicit CodeRange(Isolate* isolate);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000914 ~CodeRange() { TearDown(); }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000915
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000916 // Reserves a range of virtual memory, but does not commit any of it.
917 // Can only be called once, at heap initialization time.
918 // Returns false on failure.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000919 bool SetUp(const size_t requested_size);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000920
921 // Frees the range of virtual memory, and frees the data structures used to
922 // manage it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000923 void TearDown();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000924
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000925 bool exists() { return this != NULL && code_range_ != NULL; }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000926 Address start() {
927 if (this == NULL || code_range_ == NULL) return NULL;
928 return static_cast<Address>(code_range_->address());
929 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 bool contains(Address address) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000931 if (this == NULL || code_range_ == NULL) return false;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000932 Address start = static_cast<Address>(code_range_->address());
933 return start <= address && address < start + code_range_->size();
934 }
935
936 // Allocates a chunk of memory from the large-object portion of
937 // the code range. On platforms with no separate code range, should
938 // not be called.
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000939 MUST_USE_RESULT Address AllocateRawMemory(const size_t requested_size,
940 const size_t commit_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000941 size_t* allocated);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000942 bool CommitRawMemory(Address start, size_t length);
943 bool UncommitRawMemory(Address start, size_t length);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000944 void FreeRawMemory(Address buf, size_t length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000945
946 private:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000947 Isolate* isolate_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000948
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000949 // The reserved range of virtual memory that all code objects are put in.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000950 VirtualMemory* code_range_;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000951 // Plain old data class, just a struct plus a constructor.
952 class FreeBlock {
953 public:
954 FreeBlock(Address start_arg, size_t size_arg)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000955 : start(start_arg), size(size_arg) {
956 ASSERT(IsAddressAligned(start, MemoryChunk::kAlignment));
957 ASSERT(size >= static_cast<size_t>(Page::kPageSize));
958 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000959 FreeBlock(void* start_arg, size_t size_arg)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000960 : start(static_cast<Address>(start_arg)), size(size_arg) {
961 ASSERT(IsAddressAligned(start, MemoryChunk::kAlignment));
962 ASSERT(size >= static_cast<size_t>(Page::kPageSize));
963 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000964
965 Address start;
966 size_t size;
967 };
968
969 // Freed blocks of memory are added to the free list. When the allocation
970 // list is exhausted, the free list is sorted and merged to make the new
971 // allocation list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 List<FreeBlock> free_list_;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000973 // Memory is allocated from the free blocks on the allocation list.
974 // The block at current_allocation_block_index_ is the current block.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 List<FreeBlock> allocation_list_;
976 int current_allocation_block_index_;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000977
978 // Finds a block on the allocation list that contains at least the
979 // requested amount of memory. If none is found, sorts and merges
980 // the existing free memory blocks, and searches again.
981 // If none can be found, terminates V8 with FatalProcessOutOfMemory.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000982 void GetNextAllocationBlock(size_t requested);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000983 // Compares the start addresses of two free blocks.
984 static int CompareFreeBlockAddress(const FreeBlock* left,
985 const FreeBlock* right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000987 DISALLOW_COPY_AND_ASSIGN(CodeRange);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000988};
989
990
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000991class SkipList {
992 public:
993 SkipList() {
994 Clear();
995 }
996
997 void Clear() {
998 for (int idx = 0; idx < kSize; idx++) {
999 starts_[idx] = reinterpret_cast<Address>(-1);
1000 }
1001 }
1002
1003 Address StartFor(Address addr) {
1004 return starts_[RegionNumber(addr)];
1005 }
1006
1007 void AddObject(Address addr, int size) {
1008 int start_region = RegionNumber(addr);
1009 int end_region = RegionNumber(addr + size - kPointerSize);
1010 for (int idx = start_region; idx <= end_region; idx++) {
1011 if (starts_[idx] > addr) starts_[idx] = addr;
1012 }
1013 }
1014
1015 static inline int RegionNumber(Address addr) {
1016 return (OffsetFrom(addr) & Page::kPageAlignmentMask) >> kRegionSizeLog2;
1017 }
1018
1019 static void Update(Address addr, int size) {
1020 Page* page = Page::FromAddress(addr);
1021 SkipList* list = page->skip_list();
1022 if (list == NULL) {
1023 list = new SkipList();
1024 page->set_skip_list(list);
1025 }
1026
1027 list->AddObject(addr, size);
1028 }
1029
1030 private:
1031 static const int kRegionSizeLog2 = 13;
1032 static const int kRegionSize = 1 << kRegionSizeLog2;
1033 static const int kSize = Page::kPageSize / kRegionSize;
1034
1035 STATIC_ASSERT(Page::kPageSize % kRegionSize == 0);
1036
1037 Address starts_[kSize];
1038};
1039
1040
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001041// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001042// A space acquires chunks of memory from the operating system. The memory
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001043// allocator allocated and deallocates pages for the paged heap spaces and large
1044// pages for large object space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001045//
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001046// Each space has to manage it's own pages.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047//
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048class MemoryAllocator {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049 public:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001050 explicit MemoryAllocator(Isolate* isolate);
1051
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052 // Initializes its internal bookkeeping structures.
ager@chromium.org01fe7df2010-11-10 11:59:11 +00001053 // Max capacity of the total space and executable memory limit.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 bool SetUp(intptr_t max_capacity, intptr_t capacity_executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 void TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001058 Page* AllocatePage(
1059 intptr_t size, PagedSpace* owner, Executability executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001061 LargePage* AllocateLargePage(
1062 intptr_t object_size, Space* owner, Executability executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001064 void Free(MemoryChunk* chunk);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065
1066 // Returns the maximum available bytes of heaps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 intptr_t Available() { return capacity_ < size_ ? 0 : capacity_ - size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001069 // Returns allocated spaces in bytes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 intptr_t Size() { return size_; }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001071
ager@chromium.org01fe7df2010-11-10 11:59:11 +00001072 // Returns the maximum available executable bytes of heaps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001073 intptr_t AvailableExecutable() {
ager@chromium.org01fe7df2010-11-10 11:59:11 +00001074 if (capacity_executable_ < size_executable_) return 0;
1075 return capacity_executable_ - size_executable_;
1076 }
1077
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001078 // Returns allocated executable spaces in bytes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079 intptr_t SizeExecutable() { return size_executable_; }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001080
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001081 // Returns maximum available bytes that the old space can have.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001082 intptr_t MaxAvailable() {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001083 return (Available() / Page::kPageSize) * Page::kMaxNonCodeHeapObjectSize;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001084 }
1085
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001086 // Returns an indication of whether a pointer is in a space that has
1087 // been allocated by this MemoryAllocator.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001088 V8_INLINE bool IsOutsideAllocatedSpace(const void* address) const {
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001089 return address < lowest_ever_allocated_ ||
1090 address >= highest_ever_allocated_;
1091 }
1092
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093#ifdef DEBUG
1094 // Reports statistic info of the space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001095 void ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001096#endif
1097
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001098 // Returns a MemoryChunk in which the memory region from commit_area_size to
1099 // reserve_area_size of the chunk area is reserved but not committed, it
1100 // could be committed later by calling MemoryChunk::CommitArea.
1101 MemoryChunk* AllocateChunk(intptr_t reserve_area_size,
1102 intptr_t commit_area_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001103 Executability executable,
1104 Space* space);
1105
1106 Address ReserveAlignedMemory(size_t requested,
1107 size_t alignment,
1108 VirtualMemory* controller);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001109 Address AllocateAlignedMemory(size_t reserve_size,
1110 size_t commit_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001111 size_t alignment,
1112 Executability executable,
1113 VirtualMemory* controller);
1114
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001115 bool CommitMemory(Address addr, size_t size, Executability executable);
1116
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001117 void FreeMemory(VirtualMemory* reservation, Executability executable);
1118 void FreeMemory(Address addr, size_t size, Executability executable);
1119
1120 // Commit a contiguous block of memory from the initial chunk. Assumes that
1121 // the address is not NULL, the size is greater than zero, and that the
1122 // block is contained in the initial chunk. Returns true if it succeeded
1123 // and false otherwise.
1124 bool CommitBlock(Address start, size_t size, Executability executable);
1125
1126 // Uncommit a contiguous block of memory [start..(start+size)[.
1127 // start is not NULL, the size is greater than zero, and the
1128 // block is contained in the initial chunk. Returns true if it succeeded
1129 // and false otherwise.
1130 bool UncommitBlock(Address start, size_t size);
1131
1132 // Zaps a contiguous block of memory [start..(start+size)[ thus
1133 // filling it up with a recognizable non-NULL bit pattern.
1134 void ZapBlock(Address start, size_t size);
1135
1136 void PerformAllocationCallback(ObjectSpace space,
1137 AllocationAction action,
1138 size_t size);
1139
1140 void AddMemoryAllocationCallback(MemoryAllocationCallback callback,
1141 ObjectSpace space,
1142 AllocationAction action);
1143
1144 void RemoveMemoryAllocationCallback(
1145 MemoryAllocationCallback callback);
1146
1147 bool MemoryAllocationCallbackRegistered(
1148 MemoryAllocationCallback callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001150 static int CodePageGuardStartOffset();
1151
1152 static int CodePageGuardSize();
1153
1154 static int CodePageAreaStartOffset();
1155
1156 static int CodePageAreaEndOffset();
1157
1158 static int CodePageAreaSize() {
1159 return CodePageAreaEndOffset() - CodePageAreaStartOffset();
1160 }
1161
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001162 MUST_USE_RESULT bool CommitExecutableMemory(VirtualMemory* vm,
1163 Address start,
1164 size_t commit_size,
1165 size_t reserved_size);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001166
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167 private:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001168 Isolate* isolate_;
1169
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170 // Maximum space size in bytes.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001171 size_t capacity_;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00001172 // Maximum subset of capacity_ that can be executable
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001173 size_t capacity_executable_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 // Allocated space size in bytes.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001176 size_t size_;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001177 // Allocated executable space size in bytes.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001178 size_t size_executable_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001180 // We keep the lowest and highest addresses allocated as a quick way
1181 // of determining that pointers are outside the heap. The estimate is
1182 // conservative, i.e. not all addrsses in 'allocated' space are allocated
1183 // to our heap. The range is [lowest, highest[, inclusive on the low end
1184 // and exclusive on the high end.
1185 void* lowest_ever_allocated_;
1186 void* highest_ever_allocated_;
1187
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +00001188 struct MemoryAllocationCallbackRegistration {
1189 MemoryAllocationCallbackRegistration(MemoryAllocationCallback callback,
1190 ObjectSpace space,
1191 AllocationAction action)
1192 : callback(callback), space(space), action(action) {
1193 }
1194 MemoryAllocationCallback callback;
1195 ObjectSpace space;
1196 AllocationAction action;
1197 };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001198
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +00001199 // A List of callback that are triggered when memory is allocated or free'd
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 List<MemoryAllocationCallbackRegistration>
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +00001201 memory_allocation_callbacks_;
1202
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203 // Initializes pages in a chunk. Returns the first page address.
1204 // This function and GetChunkId() are provided for the mark-compact
1205 // collector to rebuild page headers in the from space, which is
1206 // used as a marking stack and its page headers are destroyed.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001207 Page* InitializePagesInChunk(int chunk_id, int pages_in_chunk,
1208 PagedSpace* owner);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001209
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001210 void UpdateAllocatedSpaceLimits(void* low, void* high) {
1211 lowest_ever_allocated_ = Min(lowest_ever_allocated_, low);
1212 highest_ever_allocated_ = Max(highest_ever_allocated_, high);
1213 }
1214
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001215 DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001216};
1217
1218
1219// -----------------------------------------------------------------------------
1220// Interface for heap object iterator to be implemented by all object space
1221// object iterators.
1222//
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001223// NOTE: The space specific object iterators also implements the own next()
1224// method which is used to avoid using virtual functions
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225// iterating a specific space.
1226
1227class ObjectIterator : public Malloced {
1228 public:
1229 virtual ~ObjectIterator() { }
1230
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231 virtual HeapObject* next_object() = 0;
1232};
1233
1234
1235// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236// Heap object iterator in new/old/map spaces.
1237//
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001238// A HeapObjectIterator iterates objects from the bottom of the given space
1239// to its top or from the bottom of the given page to its top.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001240//
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001241// If objects are allocated in the page during iteration the iterator may
1242// or may not iterate over those objects. The caller must create a new
1243// iterator in order to be sure to visit these new objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244class HeapObjectIterator: public ObjectIterator {
1245 public:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001246 // Creates a new object iterator in a given space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247 // If the size function is not given, the iterator calls the default
1248 // Object::Size().
1249 explicit HeapObjectIterator(PagedSpace* space);
1250 HeapObjectIterator(PagedSpace* space, HeapObjectCallback size_func);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001251 HeapObjectIterator(Page* page, HeapObjectCallback size_func);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001253 // Advance to the next object, skipping free spaces and other fillers and
1254 // skipping the special garbage section of which there is one per space.
1255 // Returns NULL when the iteration has ended.
1256 inline HeapObject* Next() {
1257 do {
1258 HeapObject* next_obj = FromCurrentPage();
1259 if (next_obj != NULL) return next_obj;
1260 } while (AdvanceToNextPage());
1261 return NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001262 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001264 virtual HeapObject* next_object() {
1265 return Next();
1266 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267
1268 private:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001269 enum PageMode { kOnePageOnly, kAllPagesInSpace };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001271 Address cur_addr_; // Current iteration point.
1272 Address cur_end_; // End iteration point.
1273 HeapObjectCallback size_func_; // Size function or NULL.
1274 PagedSpace* space_;
1275 PageMode page_mode_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001276
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001277 // Fast (inlined) path of next().
1278 inline HeapObject* FromCurrentPage();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001279
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001280 // Slow path of next(), goes into the next page. Returns false if the
1281 // iteration has ended.
1282 bool AdvanceToNextPage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283
1284 // Initializes fields.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001285 inline void Initialize(PagedSpace* owner,
1286 Address start,
1287 Address end,
1288 PageMode mode,
1289 HeapObjectCallback size_func);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290};
1291
1292
1293// -----------------------------------------------------------------------------
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001294// A PageIterator iterates the pages in a paged space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
1296class PageIterator BASE_EMBEDDED {
1297 public:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001298 explicit inline PageIterator(PagedSpace* space);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299
1300 inline bool has_next();
1301 inline Page* next();
1302
1303 private:
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001304 PagedSpace* space_;
1305 Page* prev_page_; // Previous page returned.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001306 // Next page that will be returned. Cached here so that we can use this
1307 // iterator for operations that deallocate pages.
1308 Page* next_page_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309};
1310
1311
1312// -----------------------------------------------------------------------------
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001313// A space has a circular list of pages. The next page can be accessed via
1314// Page::next_page() call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315
1316// An abstraction of allocation and relocation pointers in a page-structured
1317// space.
kasper.lund7276f142008-07-30 08:49:36 +00001318class AllocationInfo {
1319 public:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001320 AllocationInfo() : top(NULL), limit(NULL) {
1321 }
1322
1323 Address top; // Current allocation top.
1324 Address limit; // Current allocation limit.
kasper.lund7276f142008-07-30 08:49:36 +00001325
1326#ifdef DEBUG
1327 bool VerifyPagedAllocation() {
1328 return (Page::FromAllocationTop(top) == Page::FromAllocationTop(limit))
1329 && (top <= limit);
1330 }
1331#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332};
1333
1334
1335// An abstraction of the accounting statistics of a page-structured space.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001336// The 'capacity' of a space is the number of object-area bytes (i.e., not
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337// including page bookkeeping structures) currently in the space. The 'size'
1338// of a space is the number of allocated bytes, the 'waste' in the space is
1339// the number of bytes that are not allocated and not available to
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001340// allocation without reorganizing the space via a GC (e.g. small blocks due
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341// to internal fragmentation, top of page areas in map space), and the bytes
1342// 'available' is the number of unallocated bytes that are not waste. The
1343// capacity is the sum of size, waste, and available.
1344//
1345// The stats are only set by functions that ensure they stay balanced. These
1346// functions increase or decrease one of the non-capacity stats in
1347// conjunction with capacity, or else they always balance increases and
1348// decreases to the non-capacity stats.
1349class AllocationStats BASE_EMBEDDED {
1350 public:
1351 AllocationStats() { Clear(); }
1352
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001353 // Zero out all the allocation statistics (i.e., no capacity).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354 void Clear() {
1355 capacity_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 size_ = 0;
1357 waste_ = 0;
1358 }
1359
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001360 void ClearSizeWaste() {
1361 size_ = capacity_;
1362 waste_ = 0;
1363 }
1364
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001365 // Reset the allocation statistics (i.e., available = capacity with no
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 // wasted or allocated bytes).
1367 void Reset() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368 size_ = 0;
1369 waste_ = 0;
1370 }
1371
1372 // Accessors for the allocation statistics.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001373 intptr_t Capacity() { return capacity_; }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001374 intptr_t Size() { return size_; }
1375 intptr_t Waste() { return waste_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 // Grow the space by adding available bytes. They are initially marked as
1378 // being in use (part of the size), but will normally be immediately freed,
1379 // putting them on the free list and removing them from size_.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380 void ExpandSpace(int size_in_bytes) {
1381 capacity_ += size_in_bytes;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001382 size_ += size_in_bytes;
1383 ASSERT(size_ >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384 }
1385
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001386 // Shrink the space by removing available bytes. Since shrinking is done
1387 // during sweeping, bytes have been marked as being in use (part of the size)
1388 // and are hereby freed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389 void ShrinkSpace(int size_in_bytes) {
1390 capacity_ -= size_in_bytes;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001391 size_ -= size_in_bytes;
1392 ASSERT(size_ >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 }
1394
1395 // Allocate from available bytes (available -> size).
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001396 void AllocateBytes(intptr_t size_in_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397 size_ += size_in_bytes;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001398 ASSERT(size_ >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400
1401 // Free allocated bytes, making them available (size -> available).
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001402 void DeallocateBytes(intptr_t size_in_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403 size_ -= size_in_bytes;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001404 ASSERT(size_ >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 }
1406
1407 // Waste free bytes (available -> waste).
1408 void WasteBytes(int size_in_bytes) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001409 size_ -= size_in_bytes;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 waste_ += size_in_bytes;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001411 ASSERT(size_ >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412 }
1413
1414 private:
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001415 intptr_t capacity_;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001416 intptr_t size_;
1417 intptr_t waste_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418};
1419
1420
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001421// -----------------------------------------------------------------------------
1422// Free lists for old object spaces
1423//
1424// Free-list nodes are free blocks in the heap. They look like heap objects
1425// (free-list node pointers have the heap object tag, and they have a map like
1426// a heap object). They have a size and a next pointer. The next pointer is
1427// the raw address of the next free list node (or NULL).
1428class FreeListNode: public HeapObject {
1429 public:
1430 // Obtain a free-list node from a raw address. This is not a cast because
1431 // it does not check nor require that the first word at the address is a map
1432 // pointer.
1433 static FreeListNode* FromAddress(Address address) {
1434 return reinterpret_cast<FreeListNode*>(HeapObject::FromAddress(address));
1435 }
1436
1437 static inline bool IsFreeListNode(HeapObject* object);
1438
1439 // Set the size in bytes, which can be read with HeapObject::Size(). This
1440 // function also writes a map to the first word of the block so that it
1441 // looks like a heap object to the garbage collector and heap iteration
1442 // functions.
1443 void set_size(Heap* heap, int size_in_bytes);
1444
1445 // Accessors for the next field.
1446 inline FreeListNode* next();
1447 inline FreeListNode** next_address();
1448 inline void set_next(FreeListNode* next);
1449
1450 inline void Zap();
1451
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001452 static inline FreeListNode* cast(MaybeObject* maybe) {
1453 ASSERT(!maybe->IsFailure());
1454 return reinterpret_cast<FreeListNode*>(maybe);
1455 }
1456
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001457 private:
1458 static const int kNextOffset = POINTER_SIZE_ALIGN(FreeSpace::kHeaderSize);
1459
1460 DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListNode);
1461};
1462
1463
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001464// The free list category holds a pointer to the top element and a pointer to
1465// the end element of the linked list of free memory blocks.
1466class FreeListCategory {
1467 public:
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001468 FreeListCategory() :
1469 top_(NULL),
1470 end_(NULL),
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001471 available_(0) {}
1472
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001473 intptr_t Concatenate(FreeListCategory* category);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001474
1475 void Reset();
1476
1477 void Free(FreeListNode* node, int size_in_bytes);
1478
1479 FreeListNode* PickNodeFromList(int *node_size);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001480 FreeListNode* PickNodeFromList(int size_in_bytes, int *node_size);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001481
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001482 intptr_t EvictFreeListItemsInList(Page* p);
1483
1484 void RepairFreeList(Heap* heap);
1485
1486 FreeListNode** GetTopAddress() { return &top_; }
1487 FreeListNode* top() const { return top_; }
1488 void set_top(FreeListNode* top) { top_ = top; }
1489
1490 FreeListNode** GetEndAddress() { return &end_; }
1491 FreeListNode* end() const { return end_; }
1492 void set_end(FreeListNode* end) { end_ = end; }
1493
1494 int* GetAvailableAddress() { return &available_; }
1495 int available() const { return available_; }
1496 void set_available(int available) { available_ = available; }
1497
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00001498 Mutex* mutex() { return &mutex_; }
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001499
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001500#ifdef DEBUG
1501 intptr_t SumFreeList();
1502 int FreeListLength();
1503#endif
1504
1505 private:
1506 FreeListNode* top_;
1507 FreeListNode* end_;
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00001508 Mutex mutex_;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001509
1510 // Total available bytes in all blocks of this free list category.
1511 int available_;
1512};
1513
1514
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515// The free list for the old space. The free list is organized in such a way
1516// as to encourage objects allocated around the same time to be near each
1517// other. The normal way to allocate is intended to be by bumping a 'top'
1518// pointer until it hits a 'limit' pointer. When the limit is hit we need to
1519// find a new space to allocate from. This is done with the free list, which
1520// is divided up into rough categories to cut down on waste. Having finer
1521// categories would scatter allocation more.
1522
1523// The old space free list is organized in categories.
1524// 1-31 words: Such small free areas are discarded for efficiency reasons.
1525// They can be reclaimed by the compactor. However the distance between top
1526// and limit may be this small.
1527// 32-255 words: There is a list of spaces this large. It is used for top and
1528// limit when the object we need to allocate is 1-31 words in size. These
1529// spaces are called small.
1530// 256-2047 words: There is a list of spaces this large. It is used for top and
1531// limit when the object we need to allocate is 32-255 words in size. These
1532// spaces are called medium.
1533// 1048-16383 words: There is a list of spaces this large. It is used for top
1534// and limit when the object we need to allocate is 256-2047 words in size.
1535// These spaces are call large.
1536// At least 16384 words. This list is for objects of 2048 words or larger.
1537// Empty pages are added to this list. These spaces are called huge.
1538class FreeList BASE_EMBEDDED {
1539 public:
1540 explicit FreeList(PagedSpace* owner);
1541
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001542 intptr_t Concatenate(FreeList* free_list);
1543
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 // Clear the free list.
1545 void Reset();
1546
1547 // Return the number of bytes available on the free list.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001548 intptr_t available() {
1549 return small_list_.available() + medium_list_.available() +
1550 large_list_.available() + huge_list_.available();
1551 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001552
1553 // Place a node on the free list. The block of size 'size_in_bytes'
1554 // starting at 'start' is placed on the free list. The return value is the
1555 // number of bytes that have been lost due to internal fragmentation by
1556 // freeing the block. Bookkeeping information will be written to the block,
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001557 // i.e., its contents will be destroyed. The start address should be word
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001558 // aligned, and the size should be a non-zero multiple of the word size.
1559 int Free(Address start, int size_in_bytes);
1560
1561 // Allocate a block of size 'size_in_bytes' from the free list. The block
1562 // is unitialized. A failure is returned if no block is available. The
1563 // number of bytes lost to fragmentation is returned in the output parameter
1564 // 'wasted_bytes'. The size should be a non-zero multiple of the word size.
1565 MUST_USE_RESULT HeapObject* Allocate(int size_in_bytes);
1566
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001567#ifdef DEBUG
1568 void Zap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569 intptr_t SumFreeLists();
1570 bool IsVeryLong();
1571#endif
1572
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001573 // Used after booting the VM.
1574 void RepairLists(Heap* heap);
1575
danno@chromium.org2c456792011-11-11 12:00:53 +00001576 intptr_t EvictFreeListItems(Page* p);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001577
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001578 FreeListCategory* small_list() { return &small_list_; }
1579 FreeListCategory* medium_list() { return &medium_list_; }
1580 FreeListCategory* large_list() { return &large_list_; }
1581 FreeListCategory* huge_list() { return &huge_list_; }
1582
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001583 private:
1584 // The size range of blocks, in bytes.
1585 static const int kMinBlockSize = 3 * kPointerSize;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001586 static const int kMaxBlockSize = Page::kMaxNonCodeHeapObjectSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 FreeListNode* FindNodeFor(int size_in_bytes, int* node_size);
1589
1590 PagedSpace* owner_;
1591 Heap* heap_;
1592
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001593 static const int kSmallListMin = 0x20 * kPointerSize;
1594 static const int kSmallListMax = 0xff * kPointerSize;
1595 static const int kMediumListMax = 0x7ff * kPointerSize;
1596 static const int kLargeListMax = 0x3fff * kPointerSize;
1597 static const int kSmallAllocationMax = kSmallListMin - kPointerSize;
1598 static const int kMediumAllocationMax = kSmallListMax;
1599 static const int kLargeAllocationMax = kMediumListMax;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001600 FreeListCategory small_list_;
1601 FreeListCategory medium_list_;
1602 FreeListCategory large_list_;
1603 FreeListCategory huge_list_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001604
1605 DISALLOW_IMPLICIT_CONSTRUCTORS(FreeList);
1606};
1607
1608
kasper.lund7276f142008-07-30 08:49:36 +00001609class PagedSpace : public Space {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610 public:
1611 // Creates a space with a maximum capacity, and an id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001612 PagedSpace(Heap* heap,
1613 intptr_t max_capacity,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001614 AllocationSpace id,
1615 Executability executable);
kasper.lund7276f142008-07-30 08:49:36 +00001616
1617 virtual ~PagedSpace() {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618
1619 // Set up the space using the given address range of virtual memory (from
1620 // the memory allocator's initial chunk) if possible. If the block of
1621 // addresses is not big enough to contain a single page-aligned page, a
1622 // fresh chunk will be allocated.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001623 bool SetUp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624
1625 // Returns true if the space has been successfully set up and not
1626 // subsequently torn down.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001627 bool HasBeenSetUp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628
1629 // Cleans up the space, frees all pages in this space except those belonging
1630 // to the initial chunk, uncommits addresses in the initial chunk.
1631 void TearDown();
1632
1633 // Checks whether an object/address is in this space.
1634 inline bool Contains(Address a);
1635 bool Contains(HeapObject* o) { return Contains(o->address()); }
1636
kasper.lund7276f142008-07-30 08:49:36 +00001637 // Given an address occupied by a live object, return that object if it is
1638 // in this space, or Failure::Exception() if it is not. The implementation
1639 // iterates over objects in the page containing the address, the cost is
1640 // linear in the number of objects in the page. It may be slow.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001641 MUST_USE_RESULT MaybeObject* FindObject(Address addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001643 // During boot the free_space_map is created, and afterwards we may need
1644 // to write it into the free list nodes that were already created.
1645 virtual void RepairFreeListsAfterBoot();
1646
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001647 // Prepares for a mark-compact GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001648 virtual void PrepareForMarkCompact();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001649
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001650 // Current capacity without growing (Size() + Available()).
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001651 intptr_t Capacity() { return accounting_stats_.Capacity(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652
ager@chromium.org3811b432009-10-28 14:53:37 +00001653 // Total amount of memory committed for this space. For paged
1654 // spaces this equals the capacity.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001655 intptr_t CommittedMemory() { return Capacity(); }
ager@chromium.org3811b432009-10-28 14:53:37 +00001656
danno@chromium.org72204d52012-10-31 10:02:10 +00001657 // Approximate amount of physical memory committed for this space.
1658 size_t CommittedPhysicalMemory();
1659
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001660 struct SizeStats {
1661 intptr_t Total() {
1662 return small_size_ + medium_size_ + large_size_ + huge_size_;
1663 }
1664
1665 intptr_t small_size_;
1666 intptr_t medium_size_;
1667 intptr_t large_size_;
1668 intptr_t huge_size_;
1669 };
1670
1671 void ObtainFreeListStatistics(Page* p, SizeStats* sizes);
1672 void ResetFreeListStatistics();
1673
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001674 // Sets the capacity, the available space and the wasted space to zero.
1675 // The stats are rebuilt during sweeping by adding each page to the
1676 // capacity and the size when it is encountered. As free spaces are
1677 // discovered during the sweeping they are subtracted from the size and added
1678 // to the available and wasted totals.
1679 void ClearStats() {
1680 accounting_stats_.ClearSizeWaste();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001681 ResetFreeListStatistics();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001684 // Increases the number of available bytes of that space.
1685 void AddToAccountingStats(intptr_t bytes) {
1686 accounting_stats_.DeallocateBytes(bytes);
1687 }
1688
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001689 // Available bytes without growing. These are the bytes on the free list.
1690 // The bytes in the linear allocation area are not included in this total
1691 // because updating the stats would slow down allocation. New pages are
1692 // immediately added to the free list so they show up here.
1693 intptr_t Available() { return free_list_.available(); }
1694
1695 // Allocated bytes in this space. Garbage bytes that were not found due to
1696 // lazy sweeping are counted as being allocated! The bytes in the current
1697 // linear allocation area (between top and limit) are also counted here.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001698 virtual intptr_t Size() { return accounting_stats_.Size(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001700 // As size, but the bytes in lazily swept pages are estimated and the bytes
1701 // in the current linear allocation area are not included.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001702 virtual intptr_t SizeOfObjects();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001703
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001704 // Wasted bytes in this space. These are just the bytes that were thrown away
1705 // due to being too small to use for allocation. They do not include the
1706 // free bytes that were not found at all due to lazy sweeping.
1707 virtual intptr_t Waste() { return accounting_stats_.Waste(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001708
1709 // Returns the allocation pointer in this space.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001710 Address top() { return allocation_info_.top; }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001711 Address limit() { return allocation_info_.limit; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001712
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001713 // The allocation top and limit addresses.
1714 Address* allocation_top_address() { return &allocation_info_.top; }
1715 Address* allocation_limit_address() { return &allocation_info_.limit; }
1716
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001717 enum AllocationType {
1718 NEW_OBJECT,
1719 MOVE_OBJECT
1720 };
1721
kasper.lund7276f142008-07-30 08:49:36 +00001722 // Allocate the requested number of bytes in the space if possible, return a
1723 // failure object if not.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001724 MUST_USE_RESULT inline MaybeObject* AllocateRaw(
1725 int size_in_bytes,
1726 AllocationType event = NEW_OBJECT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001728 virtual bool ReserveSpace(int bytes);
1729
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001730 // Give a block of memory to the space's free list. It might be added to
1731 // the free list or accounted as waste.
1732 // If add_to_freelist is false then just accounting stats are updated and
1733 // no attempt to add area to free list is made.
1734 int Free(Address start, int size_in_bytes) {
1735 int wasted = free_list_.Free(start, size_in_bytes);
1736 accounting_stats_.DeallocateBytes(size_in_bytes - wasted);
1737 return size_in_bytes - wasted;
1738 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001739
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001740 void ResetFreeList() {
1741 free_list_.Reset();
1742 }
1743
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001744 // Set space allocation info.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001745 void SetTop(Address top, Address limit) {
1746 ASSERT(top == limit ||
1747 Page::FromAddress(top) == Page::FromAddress(limit - 1));
danno@chromium.org72204d52012-10-31 10:02:10 +00001748 MemoryChunk::UpdateHighWaterMark(allocation_info_.top);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001749 allocation_info_.top = top;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001750 allocation_info_.limit = limit;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001751 }
1752
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001753 void Allocate(int bytes) {
1754 accounting_stats_.AllocateBytes(bytes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001755 }
1756
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001757 void IncreaseCapacity(int size) {
1758 accounting_stats_.ExpandSpace(size);
1759 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001760
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001761 // Releases an unused page and shrinks the space.
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001762 void ReleasePage(Page* page, bool unlink);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001763
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001764 // The dummy page that anchors the linked list of pages.
1765 Page* anchor() { return &anchor_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001766
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001767#ifdef VERIFY_HEAP
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001768 // Verify integrity of this space.
1769 virtual void Verify(ObjectVisitor* visitor);
1770
1771 // Overridden by subclasses to verify space-specific object
1772 // properties (e.g., only maps or free-list nodes are in map space).
1773 virtual void VerifyObject(HeapObject* obj) {}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001774#endif
1775
1776#ifdef DEBUG
1777 // Print meta info and objects in this space.
1778 virtual void Print();
1779
1780 // Reports statistics for the space
1781 void ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001783 // Report code object related statistics
1784 void CollectCodeStatistics();
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001785 static void ReportCodeStatistics(Isolate* isolate);
1786 static void ResetCodeStatistics(Isolate* isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001787#endif
1788
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001789 bool was_swept_conservatively() { return was_swept_conservatively_; }
1790 void set_was_swept_conservatively(bool b) { was_swept_conservatively_ = b; }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001791
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001792 // Evacuation candidates are swept by evacuator. Needs to return a valid
1793 // result before _and_ after evacuation has finished.
1794 static bool ShouldBeSweptLazily(Page* p) {
1795 return !p->IsEvacuationCandidate() &&
1796 !p->IsFlagSet(Page::RESCAN_ON_EVACUATION) &&
1797 !p->WasSweptPrecisely();
1798 }
1799
danno@chromium.org2c456792011-11-11 12:00:53 +00001800 void SetPagesToSweep(Page* first) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001801 ASSERT(unswept_free_bytes_ == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001802 if (first == &anchor_) first = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001803 first_unswept_page_ = first;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001804 }
1805
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001806 void IncrementUnsweptFreeBytes(intptr_t by) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001807 unswept_free_bytes_ += by;
1808 }
1809
1810 void IncreaseUnsweptFreeBytes(Page* p) {
1811 ASSERT(ShouldBeSweptLazily(p));
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001812 unswept_free_bytes_ += (p->area_size() - p->LiveBytes());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001813 }
1814
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001815 void DecrementUnsweptFreeBytes(intptr_t by) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001816 unswept_free_bytes_ -= by;
1817 }
1818
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001819 void DecreaseUnsweptFreeBytes(Page* p) {
1820 ASSERT(ShouldBeSweptLazily(p));
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001821 unswept_free_bytes_ -= (p->area_size() - p->LiveBytes());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001822 }
1823
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001824 void ResetUnsweptFreeBytes() {
1825 unswept_free_bytes_ = 0;
1826 }
1827
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001828 bool AdvanceSweeper(intptr_t bytes_to_sweep);
1829
ulan@chromium.org750145a2013-03-07 15:14:13 +00001830 // When parallel sweeper threads are active and the main thread finished
1831 // its sweeping phase, this function waits for them to complete, otherwise
1832 // AdvanceSweeper with size_in_bytes is called.
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001833 bool EnsureSweeperProgress(intptr_t size_in_bytes);
1834
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001835 bool IsLazySweepingComplete() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001836 return !first_unswept_page_->is_valid();
1837 }
1838
1839 Page* FirstPage() { return anchor_.next_page(); }
1840 Page* LastPage() { return anchor_.prev_page(); }
1841
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001842 void EvictEvacuationCandidatesFromFreeLists();
1843
1844 bool CanExpand();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001845
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001846 // Returns the number of total pages in this space.
1847 int CountTotalPages();
1848
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001849 // Return size of allocatable area on a page in this space.
1850 inline int AreaSize() {
1851 return area_size_;
1852 }
1853
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001854 protected:
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001855 FreeList* free_list() { return &free_list_; }
1856
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001857 int area_size_;
1858
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001859 // Maximum capacity of this space.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001860 intptr_t max_capacity_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001861
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001862 intptr_t SizeOfFirstPage();
1863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001864 // Accounting information for this space.
1865 AllocationStats accounting_stats_;
1866
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001867 // The dummy page that anchors the double linked list of pages.
1868 Page anchor_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001870 // The space's free list.
1871 FreeList free_list_;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001873 // Normal allocation information.
1874 AllocationInfo allocation_info_;
1875
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001876 // Bytes of each page that cannot be allocated. Possibly non-zero
1877 // for pages in spaces with only fixed-size objects. Always zero
1878 // for pages in spaces with variable sized objects (those pages are
1879 // padded with free-list nodes).
1880 int page_extra_;
1881
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001882 bool was_swept_conservatively_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001884 // The first page to be swept when the lazy sweeper advances. Is set
1885 // to NULL when all pages have been swept.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001886 Page* first_unswept_page_;
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00001887
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001888 // The number of free bytes which could be reclaimed by advancing the
1889 // lazy sweeper. This is only an estimation because lazy sweeping is
1890 // done conservatively.
1891 intptr_t unswept_free_bytes_;
1892
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001893 // Expands the space by allocating a fixed number of pages. Returns false if
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001894 // it cannot allocate requested number of pages from OS, or if the hard heap
1895 // size limit has been hit.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001896 bool Expand();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001897
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001898 // Generic fast case allocation function that tries linear allocation at the
1899 // address denoted by top in allocation_info_.
1900 inline HeapObject* AllocateLinearly(int size_in_bytes);
kasper.lund7276f142008-07-30 08:49:36 +00001901
1902 // Slow path of AllocateRaw. This function is space-dependent.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001903 MUST_USE_RESULT virtual HeapObject* SlowAllocateRaw(int size_in_bytes);
kasper.lund7276f142008-07-30 08:49:36 +00001904
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00001905 friend class PageIterator;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001906 friend class SweeperThread;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001907};
1908
1909
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001910class NumberAndSizeInfo BASE_EMBEDDED {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 public:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001912 NumberAndSizeInfo() : number_(0), bytes_(0) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001913
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001914 int number() const { return number_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 void increment_number(int num) { number_ += num; }
1916
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001917 int bytes() const { return bytes_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 void increment_bytes(int size) { bytes_ += size; }
1919
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001920 void clear() {
1921 number_ = 0;
1922 bytes_ = 0;
1923 }
1924
1925 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 int number_;
1927 int bytes_;
1928};
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001929
1930
1931// HistogramInfo class for recording a single "bar" of a histogram. This
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001932// class is used for collecting statistics to print to the log file.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001933class HistogramInfo: public NumberAndSizeInfo {
1934 public:
1935 HistogramInfo() : NumberAndSizeInfo() {}
1936
1937 const char* name() { return name_; }
1938 void set_name(const char* name) { name_ = name; }
1939
1940 private:
1941 const char* name_;
1942};
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943
1944
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001945enum SemiSpaceId {
1946 kFromSpace = 0,
1947 kToSpace = 1
1948};
1949
1950
1951class SemiSpace;
1952
1953
1954class NewSpacePage : public MemoryChunk {
1955 public:
1956 // GC related flags copied from from-space to to-space when
1957 // flipping semispaces.
1958 static const intptr_t kCopyOnFlipFlagsMask =
1959 (1 << MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING) |
1960 (1 << MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING) |
1961 (1 << MemoryChunk::SCAN_ON_SCAVENGE);
1962
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001963 static const int kAreaSize = Page::kNonCodeObjectAreaSize;
1964
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001965 inline NewSpacePage* next_page() const {
1966 return static_cast<NewSpacePage*>(next_chunk());
1967 }
1968
1969 inline void set_next_page(NewSpacePage* page) {
1970 set_next_chunk(page);
1971 }
1972
1973 inline NewSpacePage* prev_page() const {
1974 return static_cast<NewSpacePage*>(prev_chunk());
1975 }
1976
1977 inline void set_prev_page(NewSpacePage* page) {
1978 set_prev_chunk(page);
1979 }
1980
1981 SemiSpace* semi_space() {
1982 return reinterpret_cast<SemiSpace*>(owner());
1983 }
1984
1985 bool is_anchor() { return !this->InNewSpace(); }
1986
1987 static bool IsAtStart(Address addr) {
1988 return (reinterpret_cast<intptr_t>(addr) & Page::kPageAlignmentMask)
1989 == kObjectStartOffset;
1990 }
1991
1992 static bool IsAtEnd(Address addr) {
1993 return (reinterpret_cast<intptr_t>(addr) & Page::kPageAlignmentMask) == 0;
1994 }
1995
1996 Address address() {
1997 return reinterpret_cast<Address>(this);
1998 }
1999
2000 // Finds the NewSpacePage containg the given address.
2001 static inline NewSpacePage* FromAddress(Address address_in_page) {
2002 Address page_start =
2003 reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address_in_page) &
2004 ~Page::kPageAlignmentMask);
2005 NewSpacePage* page = reinterpret_cast<NewSpacePage*>(page_start);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002006 return page;
2007 }
2008
2009 // Find the page for a limit address. A limit address is either an address
2010 // inside a page, or the address right after the last byte of a page.
2011 static inline NewSpacePage* FromLimit(Address address_limit) {
2012 return NewSpacePage::FromAddress(address_limit - 1);
2013 }
2014
2015 private:
2016 // Create a NewSpacePage object that is only used as anchor
2017 // for the doubly-linked list of real pages.
2018 explicit NewSpacePage(SemiSpace* owner) {
2019 InitializeAsAnchor(owner);
2020 }
2021
2022 static NewSpacePage* Initialize(Heap* heap,
2023 Address start,
2024 SemiSpace* semi_space);
2025
2026 // Intialize a fake NewSpacePage used as sentinel at the ends
2027 // of a doubly-linked list of real NewSpacePages.
2028 // Only uses the prev/next links, and sets flags to not be in new-space.
2029 void InitializeAsAnchor(SemiSpace* owner);
2030
2031 friend class SemiSpace;
2032 friend class SemiSpaceIterator;
2033};
2034
2035
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036// -----------------------------------------------------------------------------
2037// SemiSpace in young generation
2038//
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002039// A semispace is a contiguous chunk of memory holding page-like memory
2040// chunks. The mark-compact collector uses the memory of the first page in
2041// the from space as a marking stack when tracing live objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042
kasper.lund7276f142008-07-30 08:49:36 +00002043class SemiSpace : public Space {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002045 // Constructor.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002046 SemiSpace(Heap* heap, SemiSpaceId semispace)
2047 : Space(heap, NEW_SPACE, NOT_EXECUTABLE),
2048 start_(NULL),
2049 age_mark_(NULL),
2050 id_(semispace),
2051 anchor_(this),
2052 current_page_(NULL) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053
2054 // Sets up the semispace using the given chunk.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002055 void SetUp(Address start, int initial_capacity, int maximum_capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002056
2057 // Tear down the space. Heap memory was not allocated by the space, so it
2058 // is not deallocated here.
2059 void TearDown();
2060
2061 // True if the space has been set up but not torn down.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002062 bool HasBeenSetUp() { return start_ != NULL; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002063
ager@chromium.orgab99eea2009-08-25 07:05:41 +00002064 // Grow the semispace to the new capacity. The new capacity
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002065 // requested must be larger than the current capacity and less than
2066 // the maximum capacity.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00002067 bool GrowTo(int new_capacity);
2068
2069 // Shrinks the semispace to the new capacity. The new capacity
2070 // requested must be more than the amount of used memory in the
2071 // semispace and less than the current capacity.
2072 bool ShrinkTo(int new_capacity);
2073
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002074 // Returns the start address of the first page of the space.
2075 Address space_start() {
2076 ASSERT(anchor_.next_page() != &anchor_);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002077 return anchor_.next_page()->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002078 }
2079
2080 // Returns the start address of the current page of the space.
2081 Address page_low() {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002082 return current_page_->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002083 }
2084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002085 // Returns one past the end address of the space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002086 Address space_end() {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002087 return anchor_.prev_page()->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002088 }
2089
2090 // Returns one past the end address of the current page of the space.
2091 Address page_high() {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002092 return current_page_->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002093 }
2094
2095 bool AdvancePage() {
2096 NewSpacePage* next_page = current_page_->next_page();
2097 if (next_page == anchor()) return false;
2098 current_page_ = next_page;
2099 return true;
2100 }
2101
2102 // Resets the space to using the first page.
2103 void Reset();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002104
2105 // Age mark accessors.
2106 Address age_mark() { return age_mark_; }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002107 void set_age_mark(Address mark);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002108
2109 // True if the address is in the address range of this semispace (not
2110 // necessarily below the allocation pointer).
2111 bool Contains(Address a) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002112 return (reinterpret_cast<uintptr_t>(a) & address_mask_)
2113 == reinterpret_cast<uintptr_t>(start_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002114 }
2115
2116 // True if the object is a heap object in the address range of this
2117 // semispace (not necessarily below the allocation pointer).
2118 bool Contains(Object* o) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002119 return (reinterpret_cast<uintptr_t>(o) & object_mask_) == object_expected_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002120 }
2121
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002122 // If we don't have these here then SemiSpace will be abstract. However
2123 // they should never be called.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002124 virtual intptr_t Size() {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002125 UNREACHABLE();
2126 return 0;
2127 }
2128
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002129 virtual bool ReserveSpace(int bytes) {
2130 UNREACHABLE();
2131 return false;
2132 }
2133
ager@chromium.orgadd848f2009-08-13 12:44:13 +00002134 bool is_committed() { return committed_; }
2135 bool Commit();
2136 bool Uncommit();
2137
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002138 NewSpacePage* first_page() { return anchor_.next_page(); }
2139 NewSpacePage* current_page() { return current_page_; }
2140
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002141#ifdef VERIFY_HEAP
2142 virtual void Verify();
2143#endif
2144
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002145#ifdef DEBUG
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002146 virtual void Print();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002147 // Validate a range of of addresses in a SemiSpace.
2148 // The "from" address must be on a page prior to the "to" address,
2149 // in the linked page order, or it must be earlier on the same page.
2150 static void AssertValidRange(Address from, Address to);
2151#else
2152 // Do nothing.
2153 inline static void AssertValidRange(Address from, Address to) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154#endif
2155
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00002156 // Returns the current capacity of the semi space.
2157 int Capacity() { return capacity_; }
2158
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002159 // Returns the maximum capacity of the semi space.
2160 int MaximumCapacity() { return maximum_capacity_; }
2161
ager@chromium.orgab99eea2009-08-25 07:05:41 +00002162 // Returns the initial capacity of the semi space.
2163 int InitialCapacity() { return initial_capacity_; }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002164
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002165 SemiSpaceId id() { return id_; }
2166
2167 static void Swap(SemiSpace* from, SemiSpace* to);
2168
danno@chromium.org72204d52012-10-31 10:02:10 +00002169 // Approximate amount of physical memory committed for this space.
2170 size_t CommittedPhysicalMemory();
2171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 private:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002173 // Flips the semispace between being from-space and to-space.
2174 // Copies the flags into the masked positions on all pages in the space.
2175 void FlipPages(intptr_t flags, intptr_t flag_mask);
2176
2177 NewSpacePage* anchor() { return &anchor_; }
2178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 // The current and maximum capacity of the space.
2180 int capacity_;
2181 int maximum_capacity_;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00002182 int initial_capacity_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002183
2184 // The start address of the space.
2185 Address start_;
2186 // Used to govern object promotion during mark-compact collection.
2187 Address age_mark_;
2188
2189 // Masks and comparison values to test for containment in this semispace.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002190 uintptr_t address_mask_;
2191 uintptr_t object_mask_;
2192 uintptr_t object_expected_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002193
ager@chromium.orgadd848f2009-08-13 12:44:13 +00002194 bool committed_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002195 SemiSpaceId id_;
ager@chromium.orgadd848f2009-08-13 12:44:13 +00002196
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002197 NewSpacePage anchor_;
2198 NewSpacePage* current_page_;
2199
2200 friend class SemiSpaceIterator;
2201 friend class NewSpacePageIterator;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 public:
2203 TRACK_MEMORY("SemiSpace")
2204};
2205
2206
2207// A SemiSpaceIterator is an ObjectIterator that iterates over the active
2208// semispace of the heap's new space. It iterates over the objects in the
2209// semispace from a given start address (defaulting to the bottom of the
2210// semispace) to the top of the semispace. New objects allocated after the
2211// iterator is created are not iterated.
2212class SemiSpaceIterator : public ObjectIterator {
2213 public:
2214 // Create an iterator over the objects in the given space. If no start
2215 // address is given, the iterator starts from the bottom of the space. If
2216 // no size function is given, the iterator calls Object::Size().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002218 // Iterate over all of allocated to-space.
2219 explicit SemiSpaceIterator(NewSpace* space);
2220 // Iterate over all of allocated to-space, with a custome size function.
2221 SemiSpaceIterator(NewSpace* space, HeapObjectCallback size_func);
2222 // Iterate over part of allocated to-space, from start to the end
2223 // of allocation.
2224 SemiSpaceIterator(NewSpace* space, Address start);
2225 // Iterate from one address to another in the same semi-space.
2226 SemiSpaceIterator(Address from, Address to);
2227
2228 HeapObject* Next() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002229 if (current_ == limit_) return NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002230 if (NewSpacePage::IsAtEnd(current_)) {
2231 NewSpacePage* page = NewSpacePage::FromLimit(current_);
2232 page = page->next_page();
2233 ASSERT(!page->is_anchor());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002234 current_ = page->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002235 if (current_ == limit_) return NULL;
2236 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002237
2238 HeapObject* object = HeapObject::FromAddress(current_);
2239 int size = (size_func_ == NULL) ? object->Size() : size_func_(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002240
2241 current_ += size;
2242 return object;
2243 }
2244
2245 // Implementation of the ObjectIterator functions.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002246 virtual HeapObject* next_object() { return Next(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002247
2248 private:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002249 void Initialize(Address start,
2250 Address end,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 HeapObjectCallback size_func);
2252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002253 // The current iteration point.
2254 Address current_;
2255 // The end of iteration.
2256 Address limit_;
2257 // The callback function.
2258 HeapObjectCallback size_func_;
2259};
2260
2261
2262// -----------------------------------------------------------------------------
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002263// A PageIterator iterates the pages in a semi-space.
2264class NewSpacePageIterator BASE_EMBEDDED {
2265 public:
2266 // Make an iterator that runs over all pages in to-space.
2267 explicit inline NewSpacePageIterator(NewSpace* space);
2268
2269 // Make an iterator that runs over all pages in the given semispace,
2270 // even those not used in allocation.
2271 explicit inline NewSpacePageIterator(SemiSpace* space);
2272
2273 // Make iterator that iterates from the page containing start
2274 // to the page that contains limit in the same semispace.
2275 inline NewSpacePageIterator(Address start, Address limit);
2276
2277 inline bool has_next();
2278 inline NewSpacePage* next();
2279
2280 private:
2281 NewSpacePage* prev_page_; // Previous page returned.
2282 // Next page that will be returned. Cached here so that we can use this
2283 // iterator for operations that deallocate pages.
2284 NewSpacePage* next_page_;
2285 // Last page returned.
2286 NewSpacePage* last_page_;
2287};
2288
2289
2290// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002291// The young generation space.
2292//
2293// The new space consists of a contiguous pair of semispaces. It simply
2294// forwards most functions to the appropriate semispace.
2295
kasper.lund7276f142008-07-30 08:49:36 +00002296class NewSpace : public Space {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002297 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002298 // Constructor.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002299 explicit NewSpace(Heap* heap)
2300 : Space(heap, NEW_SPACE, NOT_EXECUTABLE),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002301 to_space_(heap, kToSpace),
2302 from_space_(heap, kFromSpace),
2303 reservation_(),
2304 inline_allocation_limit_step_(0) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002305
2306 // Sets up the new space using the given chunk.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002307 bool SetUp(int reserved_semispace_size_, int max_semispace_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002308
2309 // Tears down the space. Heap memory was not allocated by the space, so it
2310 // is not deallocated here.
2311 void TearDown();
2312
2313 // True if the space has been set up but not torn down.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002314 bool HasBeenSetUp() {
2315 return to_space_.HasBeenSetUp() && from_space_.HasBeenSetUp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002316 }
2317
2318 // Flip the pair of spaces.
2319 void Flip();
2320
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00002321 // Grow the capacity of the semispaces. Assumes that they are not at
ager@chromium.orgab99eea2009-08-25 07:05:41 +00002322 // their maximum capacity.
2323 void Grow();
2324
2325 // Shrink the capacity of the semispaces.
2326 void Shrink();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002327
2328 // True if the address or object lies in the address range of either
2329 // semispace (not necessarily below the allocation pointer).
2330 bool Contains(Address a) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002331 return (reinterpret_cast<uintptr_t>(a) & address_mask_)
2332 == reinterpret_cast<uintptr_t>(start_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002333 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002334
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002335 bool Contains(Object* o) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002336 Address a = reinterpret_cast<Address>(o);
2337 return (reinterpret_cast<uintptr_t>(a) & object_mask_) == object_expected_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002338 }
2339
2340 // Return the allocated bytes in the active semispace.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002341 virtual intptr_t Size() {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002342 return pages_used_ * NewSpacePage::kAreaSize +
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002343 static_cast<int>(top() - to_space_.page_low());
2344 }
2345
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002346 // The same, but returning an int. We have to have the one that returns
2347 // intptr_t because it is inherited, but if we know we are dealing with the
2348 // new space, which can't get as big as the other spaces then this is useful:
2349 int SizeAsInt() { return static_cast<int>(Size()); }
ager@chromium.org3811b432009-10-28 14:53:37 +00002350
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002351 // Return the current capacity of a semispace.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002352 intptr_t EffectiveCapacity() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002353 SLOW_ASSERT(to_space_.Capacity() == from_space_.Capacity());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002354 return (to_space_.Capacity() / Page::kPageSize) * NewSpacePage::kAreaSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002355 }
2356
2357 // Return the current capacity of a semispace.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002358 intptr_t Capacity() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002359 ASSERT(to_space_.Capacity() == from_space_.Capacity());
2360 return to_space_.Capacity();
2361 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002362
2363 // Return the total amount of memory committed for new space.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002364 intptr_t CommittedMemory() {
ager@chromium.org3811b432009-10-28 14:53:37 +00002365 if (from_space_.is_committed()) return 2 * Capacity();
2366 return Capacity();
2367 }
2368
danno@chromium.org72204d52012-10-31 10:02:10 +00002369 // Approximate amount of physical memory committed for this space.
2370 size_t CommittedPhysicalMemory();
2371
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002372 // Return the available bytes without growing.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002373 intptr_t Available() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002374 return Capacity() - Size();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002375 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002376
2377 // Return the maximum capacity of a semispace.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002378 int MaximumCapacity() {
2379 ASSERT(to_space_.MaximumCapacity() == from_space_.MaximumCapacity());
2380 return to_space_.MaximumCapacity();
2381 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002382
ager@chromium.orgab99eea2009-08-25 07:05:41 +00002383 // Returns the initial capacity of a semispace.
2384 int InitialCapacity() {
2385 ASSERT(to_space_.InitialCapacity() == from_space_.InitialCapacity());
2386 return to_space_.InitialCapacity();
2387 }
2388
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002389 // Return the address of the allocation pointer in the active semispace.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002390 Address top() {
2391 ASSERT(to_space_.current_page()->ContainsLimit(allocation_info_.top));
2392 return allocation_info_.top;
2393 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002394 // Return the address of the first object in the active semispace.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002395 Address bottom() { return to_space_.space_start(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002396
2397 // Get the age mark of the inactive semispace.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002398 Address age_mark() { return from_space_.age_mark(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002399 // Set the age mark in the active semispace.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002400 void set_age_mark(Address mark) { to_space_.set_age_mark(mark); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002401
2402 // The start address of the space and a bit mask. Anding an address in the
2403 // new space with the mask will result in the start address.
2404 Address start() { return start_; }
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00002405 uintptr_t mask() { return address_mask_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002406
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002407 INLINE(uint32_t AddressToMarkbitIndex(Address addr)) {
2408 ASSERT(Contains(addr));
2409 ASSERT(IsAligned(OffsetFrom(addr), kPointerSize) ||
2410 IsAligned(OffsetFrom(addr) - 1, kPointerSize));
2411 return static_cast<uint32_t>(addr - start_) >> kPointerSizeLog2;
2412 }
2413
2414 INLINE(Address MarkbitIndexToAddress(uint32_t index)) {
2415 return reinterpret_cast<Address>(index << kPointerSizeLog2);
2416 }
2417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002418 // The allocation top and limit addresses.
2419 Address* allocation_top_address() { return &allocation_info_.top; }
2420 Address* allocation_limit_address() { return &allocation_info_.limit; }
2421
danno@chromium.orgc612e022011-11-10 11:38:15 +00002422 MUST_USE_RESULT INLINE(MaybeObject* AllocateRaw(int size_in_bytes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002423
2424 // Reset the allocation pointer to the beginning of the active semispace.
2425 void ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002426
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002427 void LowerInlineAllocationLimit(intptr_t step) {
2428 inline_allocation_limit_step_ = step;
2429 if (step == 0) {
2430 allocation_info_.limit = to_space_.page_high();
2431 } else {
2432 allocation_info_.limit = Min(
2433 allocation_info_.top + inline_allocation_limit_step_,
2434 allocation_info_.limit);
2435 }
2436 top_on_previous_step_ = allocation_info_.top;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002437 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002438
2439 // Get the extent of the inactive semispace (for use as a marking stack,
2440 // or to zap it). Notice: space-addresses are not necessarily on the
2441 // same page, so FromSpaceStart() might be above FromSpaceEnd().
2442 Address FromSpacePageLow() { return from_space_.page_low(); }
2443 Address FromSpacePageHigh() { return from_space_.page_high(); }
2444 Address FromSpaceStart() { return from_space_.space_start(); }
2445 Address FromSpaceEnd() { return from_space_.space_end(); }
2446
2447 // Get the extent of the active semispace's pages' memory.
2448 Address ToSpaceStart() { return to_space_.space_start(); }
2449 Address ToSpaceEnd() { return to_space_.space_end(); }
2450
2451 inline bool ToSpaceContains(Address address) {
2452 return to_space_.Contains(address);
2453 }
2454 inline bool FromSpaceContains(Address address) {
2455 return from_space_.Contains(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002456 }
2457
2458 // True if the object is a heap object in the address range of the
2459 // respective semispace (not necessarily below the allocation pointer of the
2460 // semispace).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002461 inline bool ToSpaceContains(Object* o) { return to_space_.Contains(o); }
2462 inline bool FromSpaceContains(Object* o) { return from_space_.Contains(o); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002463
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002464 // Try to switch the active semispace to a new, empty, page.
2465 // Returns false if this isn't possible or reasonable (i.e., there
2466 // are no pages, or the current page is already empty), or true
2467 // if successful.
2468 bool AddFreshPage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002469
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002470 virtual bool ReserveSpace(int bytes);
2471
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002472#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002473 // Verify the active semispace.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002474 virtual void Verify();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002475#endif
2476
2477#ifdef DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002478 // Print the active semispace.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002479 virtual void Print() { to_space_.Print(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002480#endif
2481
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002482 // Iterates the active semispace to collect statistics.
2483 void CollectStatistics();
2484 // Reports previously collected statistics of the active semispace.
2485 void ReportStatistics();
2486 // Clears previously collected statistics.
2487 void ClearHistograms();
2488
2489 // Record the allocation or promotion of a heap object. Note that we don't
2490 // record every single allocation, but only those that happen in the
2491 // to space during a scavenge GC.
2492 void RecordAllocation(HeapObject* obj);
2493 void RecordPromotion(HeapObject* obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002494
ager@chromium.orgadd848f2009-08-13 12:44:13 +00002495 // Return whether the operation succeded.
2496 bool CommitFromSpaceIfNeeded() {
2497 if (from_space_.is_committed()) return true;
2498 return from_space_.Commit();
2499 }
2500
2501 bool UncommitFromSpace() {
2502 if (!from_space_.is_committed()) return true;
2503 return from_space_.Uncommit();
2504 }
2505
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002506 inline intptr_t inline_allocation_limit_step() {
2507 return inline_allocation_limit_step_;
2508 }
2509
2510 SemiSpace* active_space() { return &to_space_; }
2511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002512 private:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002513 // Update allocation info to match the current to-space page.
2514 void UpdateAllocationInfo();
2515
2516 Address chunk_base_;
2517 uintptr_t chunk_size_;
2518
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002519 // The semispaces.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002520 SemiSpace to_space_;
2521 SemiSpace from_space_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002522 VirtualMemory reservation_;
2523 int pages_used_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002524
2525 // Start address and bit mask for containment testing.
2526 Address start_;
ager@chromium.org9085a012009-05-11 19:22:57 +00002527 uintptr_t address_mask_;
2528 uintptr_t object_mask_;
2529 uintptr_t object_expected_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002530
2531 // Allocation pointer and limit for normal allocation and allocation during
2532 // mark-compact collection.
2533 AllocationInfo allocation_info_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002534
2535 // When incremental marking is active we will set allocation_info_.limit
2536 // to be lower than actual limit and then will gradually increase it
2537 // in steps to guarantee that we do incremental marking steps even
2538 // when all allocation is performed from inlined generated code.
2539 intptr_t inline_allocation_limit_step_;
2540
2541 Address top_on_previous_step_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002542
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002543 HistogramInfo* allocated_histogram_;
2544 HistogramInfo* promoted_histogram_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002545
danno@chromium.orgc612e022011-11-10 11:38:15 +00002546 MUST_USE_RESULT MaybeObject* SlowAllocateRaw(int size_in_bytes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002547
2548 friend class SemiSpaceIterator;
2549
2550 public:
2551 TRACK_MEMORY("NewSpace")
2552};
2553
2554
2555// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002556// Old object space (excluding map objects)
2557
2558class OldSpace : public PagedSpace {
2559 public:
2560 // Creates an old space object with a given maximum capacity.
2561 // The constructor does not allocate pages from OS.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002562 OldSpace(Heap* heap,
2563 intptr_t max_capacity,
2564 AllocationSpace id,
2565 Executability executable)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002566 : PagedSpace(heap, max_capacity, id, executable) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002567 page_extra_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002568 }
2569
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002570 // The limit of allocation for a page in this space.
2571 virtual Address PageAllocationLimit(Page* page) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002572 return page->area_end();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002573 }
2574
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002575 public:
2576 TRACK_MEMORY("OldSpace")
2577};
2578
2579
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002580// For contiguous spaces, top should be in the space (or at the end) and limit
2581// should be the end of the space.
2582#define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002583 SLOW_ASSERT((space).page_low() <= (info).top \
2584 && (info).top <= (space).page_high() \
2585 && (info).limit <= (space).page_high())
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002586
2587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002588// -----------------------------------------------------------------------------
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002589// Old space for objects of a fixed size
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002590
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002591class FixedSpace : public PagedSpace {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002592 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002593 FixedSpace(Heap* heap,
2594 intptr_t max_capacity,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002595 AllocationSpace id,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002596 int object_size_in_bytes)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002597 : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE),
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002598 object_size_in_bytes_(object_size_in_bytes) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002599 page_extra_ = Page::kNonCodeObjectAreaSize % object_size_in_bytes;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002601
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002602 // The limit of allocation for a page in this space.
2603 virtual Address PageAllocationLimit(Page* page) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002604 return page->area_end() - page_extra_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002605 }
2606
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002607 int object_size_in_bytes() { return object_size_in_bytes_; }
2608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002609 // Prepares for a mark-compact GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002610 virtual void PrepareForMarkCompact();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002611
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002612 private:
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002613 // The size of objects in this space.
2614 int object_size_in_bytes_;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002615};
2616
2617
2618// -----------------------------------------------------------------------------
2619// Old space for all map objects
2620
2621class MapSpace : public FixedSpace {
2622 public:
2623 // Creates a map space object with a maximum capacity.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002624 MapSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002625 : FixedSpace(heap, max_capacity, id, Map::kSize),
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002626 max_map_space_pages_(kMaxMapPageIndex - 1) {
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002627 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002628
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002629 // Given an index, returns the page address.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002630 // TODO(1600): this limit is artifical just to keep code compilable
2631 static const int kMaxMapPageIndex = 1 << 16;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002632
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002633 virtual int RoundSizeDownToObjectAlignment(int size) {
2634 if (IsPowerOf2(Map::kSize)) {
2635 return RoundDown(size, Map::kSize);
2636 } else {
2637 return (size / Map::kSize) * Map::kSize;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002638 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002639 }
2640
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002641 protected:
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002642 virtual void VerifyObject(HeapObject* obj);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002643
2644 private:
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002645 static const int kMapsPerPage = Page::kNonCodeObjectAreaSize / Map::kSize;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002646
2647 // Do map space compaction if there is a page gap.
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002648 int CompactionThreshold() {
2649 return kMapsPerPage * (max_map_space_pages_ - 1);
2650 }
2651
2652 const int max_map_space_pages_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002653
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002654 public:
2655 TRACK_MEMORY("MapSpace")
2656};
2657
2658
2659// -----------------------------------------------------------------------------
danno@chromium.org41728482013-06-12 22:31:22 +00002660// Old space for simple property cell objects
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002661
2662class CellSpace : public FixedSpace {
2663 public:
2664 // Creates a property cell space object with a maximum capacity.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002665 CellSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
danno@chromium.org41728482013-06-12 22:31:22 +00002666 : FixedSpace(heap, max_capacity, id, Cell::kSize)
2667 {}
2668
2669 virtual int RoundSizeDownToObjectAlignment(int size) {
2670 if (IsPowerOf2(Cell::kSize)) {
2671 return RoundDown(size, Cell::kSize);
2672 } else {
2673 return (size / Cell::kSize) * Cell::kSize;
2674 }
2675 }
2676
2677 protected:
2678 virtual void VerifyObject(HeapObject* obj);
2679
2680 public:
2681 TRACK_MEMORY("CellSpace")
2682};
2683
2684
2685// -----------------------------------------------------------------------------
2686// Old space for all global object property cell objects
2687
2688class PropertyCellSpace : public FixedSpace {
2689 public:
2690 // Creates a property cell space object with a maximum capacity.
2691 PropertyCellSpace(Heap* heap, intptr_t max_capacity,
2692 AllocationSpace id)
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002693 : FixedSpace(heap, max_capacity, id, PropertyCell::kSize)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002694 {}
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002695
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002696 virtual int RoundSizeDownToObjectAlignment(int size) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002697 if (IsPowerOf2(PropertyCell::kSize)) {
2698 return RoundDown(size, PropertyCell::kSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002699 } else {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002700 return (size / PropertyCell::kSize) * PropertyCell::kSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002701 }
2702 }
2703
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002704 protected:
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002705 virtual void VerifyObject(HeapObject* obj);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002706
2707 public:
danno@chromium.org41728482013-06-12 22:31:22 +00002708 TRACK_MEMORY("PropertyCellSpace")
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002709};
2710
2711
2712// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002713// Large objects ( > Page::kMaxHeapObjectSize ) are allocated and managed by
2714// the large object space. A large object is allocated from OS heap with
2715// extra padding bytes (Page::kPageSize + Page::kObjectStartOffset).
2716// A large object always starts at Page::kObjectStartOffset to a page.
2717// Large objects do not move during garbage collections.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002718
kasper.lund7276f142008-07-30 08:49:36 +00002719class LargeObjectSpace : public Space {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002721 LargeObjectSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002722 virtual ~LargeObjectSpace() {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002723
2724 // Initializes internal data structures.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002725 bool SetUp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002726
2727 // Releases internal resources, frees objects in this space.
2728 void TearDown();
2729
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002730 static intptr_t ObjectSizeFor(intptr_t chunk_size) {
2731 if (chunk_size <= (Page::kPageSize + Page::kObjectStartOffset)) return 0;
2732 return chunk_size - Page::kPageSize - Page::kObjectStartOffset;
2733 }
2734
2735 // Shared implementation of AllocateRaw, AllocateRawCode and
2736 // AllocateRawFixedArray.
2737 MUST_USE_RESULT MaybeObject* AllocateRaw(int object_size,
2738 Executability executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002739
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002740 // Available bytes for objects in this space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002741 inline intptr_t Available();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002742
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002743 virtual intptr_t Size() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744 return size_;
2745 }
2746
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002747 virtual intptr_t SizeOfObjects() {
2748 return objects_size_;
2749 }
2750
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002751 intptr_t CommittedMemory() {
2752 return Size();
2753 }
2754
danno@chromium.org72204d52012-10-31 10:02:10 +00002755 // Approximate amount of physical memory committed for this space.
2756 size_t CommittedPhysicalMemory();
2757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002758 int PageCount() {
2759 return page_count_;
2760 }
2761
2762 // Finds an object for a given address, returns Failure::Exception()
2763 // if it is not found. The function iterates through all objects in this
2764 // space, may be slow.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002765 MaybeObject* FindObject(Address a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002766
jkummerow@chromium.org531dfe82012-03-20 13:01:16 +00002767 // Finds a large object page containing the given address, returns NULL
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002768 // if such a page doesn't exist.
jkummerow@chromium.org531dfe82012-03-20 13:01:16 +00002769 LargePage* FindPage(Address a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002770
2771 // Frees unmarked objects.
2772 void FreeUnmarkedObjects();
2773
2774 // Checks whether a heap object is in this space; O(1).
2775 bool Contains(HeapObject* obj);
2776
2777 // Checks whether the space is empty.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002778 bool IsEmpty() { return first_page_ == NULL; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002779
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002780 // See the comments for ReserveSpace in the Space class. This has to be
2781 // called after ReserveSpace has been called on the paged spaces, since they
2782 // may use some memory, leaving less for large objects.
2783 virtual bool ReserveSpace(int bytes);
2784
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002785 LargePage* first_page() { return first_page_; }
2786
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002787#ifdef VERIFY_HEAP
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002788 virtual void Verify();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002789#endif
2790
2791#ifdef DEBUG
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002792 virtual void Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002793 void ReportStatistics();
2794 void CollectCodeStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002795#endif
2796 // Checks whether an address is in the object area in this space. It
2797 // iterates all objects in the space. May be slow.
2798 bool SlowContains(Address addr) { return !FindObject(addr)->IsFailure(); }
2799
2800 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002801 intptr_t max_capacity_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002802 // The head of the linked list of large object chunks.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002803 LargePage* first_page_;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002804 intptr_t size_; // allocated bytes
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002805 int page_count_; // number of chunks
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002806 intptr_t objects_size_; // size of objects
jkummerow@chromium.org531dfe82012-03-20 13:01:16 +00002807 // Map MemoryChunk::kAlignment-aligned chunks to large pages covering them
2808 HashMap chunk_map_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002809
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00002810 friend class LargeObjectIterator;
2811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002812 public:
2813 TRACK_MEMORY("LargeObjectSpace")
2814};
2815
2816
2817class LargeObjectIterator: public ObjectIterator {
2818 public:
2819 explicit LargeObjectIterator(LargeObjectSpace* space);
2820 LargeObjectIterator(LargeObjectSpace* space, HeapObjectCallback size_func);
2821
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002822 HeapObject* Next();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002823
2824 // implementation of ObjectIterator.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002825 virtual HeapObject* next_object() { return Next(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002826
2827 private:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002828 LargePage* current_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002829 HeapObjectCallback size_func_;
2830};
2831
2832
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002833// Iterates over the chunks (pages and large object pages) that can contain
2834// pointers to new space.
2835class PointerChunkIterator BASE_EMBEDDED {
2836 public:
2837 inline explicit PointerChunkIterator(Heap* heap);
2838
2839 // Return NULL when the iterator is done.
2840 MemoryChunk* next() {
2841 switch (state_) {
2842 case kOldPointerState: {
2843 if (old_pointer_iterator_.has_next()) {
2844 return old_pointer_iterator_.next();
2845 }
2846 state_ = kMapState;
2847 // Fall through.
2848 }
2849 case kMapState: {
2850 if (map_iterator_.has_next()) {
2851 return map_iterator_.next();
2852 }
2853 state_ = kLargeObjectState;
2854 // Fall through.
2855 }
2856 case kLargeObjectState: {
2857 HeapObject* heap_object;
2858 do {
2859 heap_object = lo_iterator_.Next();
2860 if (heap_object == NULL) {
2861 state_ = kFinishedState;
2862 return NULL;
2863 }
2864 // Fixed arrays are the only pointer-containing objects in large
2865 // object space.
2866 } while (!heap_object->IsFixedArray());
2867 MemoryChunk* answer = MemoryChunk::FromAddress(heap_object->address());
2868 return answer;
2869 }
2870 case kFinishedState:
2871 return NULL;
2872 default:
2873 break;
2874 }
2875 UNREACHABLE();
2876 return NULL;
2877 }
2878
2879
2880 private:
2881 enum State {
2882 kOldPointerState,
2883 kMapState,
2884 kLargeObjectState,
2885 kFinishedState
2886 };
2887 State state_;
2888 PageIterator old_pointer_iterator_;
2889 PageIterator map_iterator_;
2890 LargeObjectIterator lo_iterator_;
2891};
2892
2893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002894#ifdef DEBUG
2895struct CommentStatistic {
2896 const char* comment;
2897 int size;
2898 int count;
2899 void Clear() {
2900 comment = NULL;
2901 size = 0;
2902 count = 0;
2903 }
2904 // Must be small, since an iteration is used for lookup.
2905 static const int kMaxComments = 64;
2906};
2907#endif
2908
2909
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002910} } // namespace v8::internal
2911
2912#endif // V8_SPACES_H_