1// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31#include "cctest.h"
32
33using namespace v8::internal;
34
35static void VerifyRSet(Address page_start) {
36#ifdef DEBUG
37  Page::set_rset_state(Page::IN_USE);
38#endif
39
40  Page* p = Page::FromAddress(page_start);
41
42  p->ClearRSet();
43
44  for (Address addr = p->ObjectAreaStart();
45       addr < p->ObjectAreaEnd();
46       addr += kPointerSize) {
47    CHECK(!Page::IsRSetSet(addr, 0));
48  }
49
50  for (Address addr = p->ObjectAreaStart();
51       addr < p->ObjectAreaEnd();
52       addr += kPointerSize) {
53    Page::SetRSet(addr, 0);
54  }
55
56  for (Address addr = p->ObjectAreaStart();
57       addr < p->ObjectAreaEnd();
58       addr += kPointerSize) {
59    CHECK(Page::IsRSetSet(addr, 0));
60  }
61}
62
63
64TEST(Page) {
65#ifdef DEBUG
66  Page::set_rset_state(Page::NOT_IN_USE);
67#endif
68
69  byte* mem = NewArray<byte>(2*Page::kPageSize);
70  CHECK(mem != NULL);
71
72  Address start = reinterpret_cast<Address>(mem);
73  Address page_start = RoundUp(start, Page::kPageSize);
74
75  Page* p = Page::FromAddress(page_start);
76  CHECK(p->address() == page_start);
77  CHECK(p->is_valid());
78
79  p->opaque_header = 0;
80  p->is_normal_page = 0x1;
81  CHECK(!p->next_page()->is_valid());
82
83  CHECK(p->ObjectAreaStart() == page_start + Page::kObjectStartOffset);
84  CHECK(p->ObjectAreaEnd() == page_start + Page::kPageSize);
85
86  CHECK(p->Offset(page_start + Page::kObjectStartOffset) ==
87        Page::kObjectStartOffset);
88  CHECK(p->Offset(page_start + Page::kPageSize) == Page::kPageSize);
89
90  CHECK(p->OffsetToAddress(Page::kObjectStartOffset) == p->ObjectAreaStart());
91  CHECK(p->OffsetToAddress(Page::kPageSize) == p->ObjectAreaEnd());
92
93  // test remember set
94  VerifyRSet(page_start);
95
96  DeleteArray(mem);
97}
98
99
100TEST(MemoryAllocator) {
101  CHECK(Heap::ConfigureHeapDefault());
102  CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
103
104  OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
105  int total_pages = 0;
106  int requested = 2;
107  int allocated;
108  // If we request two pages, we should get one or two.
109  Page* first_page =
110      MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
111  CHECK(first_page->is_valid());
112  CHECK(allocated > 0 && allocated <= 2);
113  total_pages += allocated;
114
115  Page* last_page = first_page;
116  for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
117    CHECK(MemoryAllocator::IsPageInSpace(p, &faked_space));
118    last_page = p;
119  }
120
121  // Again, we should get one or two pages.
122  Page* others =
123      MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
124  CHECK(others->is_valid());
125  CHECK(allocated > 0 && allocated <= 2);
126  total_pages += allocated;
127
128  MemoryAllocator::SetNextPage(last_page, others);
129  int page_count = 0;
130  for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
131    CHECK(MemoryAllocator::IsPageInSpace(p, &faked_space));
132    page_count++;
133  }
134  CHECK(total_pages == page_count);
135
136  Page* second_page = first_page->next_page();
137  CHECK(second_page->is_valid());
138
139  // Freeing pages at the first chunk starting at or after the second page
140  // should free the entire second chunk.  It will return the last page in the
141  // first chunk (if the second page was in the first chunk) or else an
142  // invalid page (if the second page was the start of the second chunk).
143  Page* free_return = MemoryAllocator::FreePages(second_page);
144  CHECK(free_return == last_page || !free_return->is_valid());
145  MemoryAllocator::SetNextPage(first_page, free_return);
146
147  // Freeing pages in the first chunk starting at the first page should free
148  // the first chunk and return an invalid page.
149  Page* invalid_page = MemoryAllocator::FreePages(first_page);
150  CHECK(!invalid_page->is_valid());
151
152  MemoryAllocator::TearDown();
153}
154
155
156TEST(NewSpace) {
157  CHECK(Heap::ConfigureHeapDefault());
158  CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
159
160  NewSpace new_space;
161
162  void* chunk =
163      MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
164  CHECK(chunk != NULL);
165  Address start = RoundUp(static_cast<Address>(chunk),
166                          2 * Heap::ReservedSemiSpaceSize());
167  CHECK(new_space.Setup(start, 2 * Heap::ReservedSemiSpaceSize()));
168  CHECK(new_space.HasBeenSetup());
169
170  while (new_space.Available() >= Page::kMaxHeapObjectSize) {
171    Object* obj = new_space.AllocateRaw(Page::kMaxHeapObjectSize);
172    CHECK(!obj->IsFailure());
173    CHECK(new_space.Contains(HeapObject::cast(obj)));
174  }
175
176  new_space.TearDown();
177  MemoryAllocator::TearDown();
178}
179
180
181TEST(OldSpace) {
182  CHECK(Heap::ConfigureHeapDefault());
183  CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
184
185  OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(),
186                             OLD_POINTER_SPACE,
187                             NOT_EXECUTABLE);
188  CHECK(s != NULL);
189
190  void* chunk =
191      MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
192  CHECK(chunk != NULL);
193  Address start = static_cast<Address>(chunk);
194  size_t size = RoundUp(start, 2 * Heap::ReservedSemiSpaceSize()) - start;
195
196  CHECK(s->Setup(start, size));
197
198  while (s->Available() > 0) {
199    Object* obj = s->AllocateRaw(Page::kMaxHeapObjectSize);
200    CHECK(!obj->IsFailure());
201  }
202
203  s->TearDown();
204  delete s;
205  MemoryAllocator::TearDown();
206}
207
208
209TEST(LargeObjectSpace) {
210  CHECK(Heap::Setup(false));
211
212  LargeObjectSpace* lo = Heap::lo_space();
213  CHECK(lo != NULL);
214
215  Map* faked_map = reinterpret_cast<Map*>(HeapObject::FromAddress(0));
216  int lo_size = Page::kPageSize;
217
218  Object* obj = lo->AllocateRaw(lo_size);
219  CHECK(!obj->IsFailure());
220  CHECK(obj->IsHeapObject());
221
222  HeapObject* ho = HeapObject::cast(obj);
223  ho->set_map(faked_map);
224
225  CHECK(lo->Contains(HeapObject::cast(obj)));
226
227  CHECK(lo->FindObject(ho->address()) == obj);
228
229  CHECK(lo->Contains(ho));
230
231  while (true) {
232    int available = lo->Available();
233    obj = lo->AllocateRaw(lo_size);
234    if (obj->IsFailure()) break;
235    HeapObject::cast(obj)->set_map(faked_map);
236    CHECK(lo->Available() < available);
237  };
238
239  CHECK(!lo->IsEmpty());
240
241  obj = lo->AllocateRaw(lo_size);
242  CHECK(obj->IsFailure());
243
244  lo->TearDown();
245  delete lo;
246
247  MemoryAllocator::TearDown();
248}
249