test-spaces.cc 7.54 KB
Newer Older
1
// Copyright 2006-2008 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <stdlib.h>

#include "v8.h"
#include "cctest.h"

using namespace v8::internal;

35
static void VerifyRegionMarking(Address page_start) {
36 37
  Page* p = Page::FromAddress(page_start);

38
  p->SetRegionMarks(Page::kAllRegionsCleanMarks);
39 40 41 42

  for (Address addr = p->ObjectAreaStart();
       addr < p->ObjectAreaEnd();
       addr += kPointerSize) {
43
    CHECK(!Page::FromAddress(addr)->IsRegionDirty(addr));
44 45 46 47 48
  }

  for (Address addr = p->ObjectAreaStart();
       addr < p->ObjectAreaEnd();
       addr += kPointerSize) {
49
    Page::FromAddress(addr)->MarkRegionDirty(addr);
50 51 52 53 54
  }

  for (Address addr = p->ObjectAreaStart();
       addr < p->ObjectAreaEnd();
       addr += kPointerSize) {
55
    CHECK(Page::FromAddress(addr)->IsRegionDirty(addr));
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  }
}


TEST(Page) {
  byte* mem = NewArray<byte>(2*Page::kPageSize);
  CHECK(mem != NULL);

  Address start = reinterpret_cast<Address>(mem);
  Address page_start = RoundUp(start, Page::kPageSize);

  Page* p = Page::FromAddress(page_start);
  CHECK(p->address() == page_start);
  CHECK(p->is_valid());

  p->opaque_header = 0;
72
  p->SetIsLargeObjectPage(false);
73 74 75 76 77 78 79 80 81 82 83 84
  CHECK(!p->next_page()->is_valid());

  CHECK(p->ObjectAreaStart() == page_start + Page::kObjectStartOffset);
  CHECK(p->ObjectAreaEnd() == page_start + Page::kPageSize);

  CHECK(p->Offset(page_start + Page::kObjectStartOffset) ==
        Page::kObjectStartOffset);
  CHECK(p->Offset(page_start + Page::kPageSize) == Page::kPageSize);

  CHECK(p->OffsetToAddress(Page::kObjectStartOffset) == p->ObjectAreaStart());
  CHECK(p->OffsetToAddress(Page::kPageSize) == p->ObjectAreaEnd());

85 86
  // test region marking
  VerifyRegionMarking(page_start);
87 88 89 90 91 92 93

  DeleteArray(mem);
}


TEST(MemoryAllocator) {
  CHECK(Heap::ConfigureHeapDefault());
94
  CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
95

96
  OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
97
  int total_pages = 0;
98
  int requested = MemoryAllocator::kPagesPerChunk;
99
  int allocated;
100
  // If we request n pages, we should get n or n - 1.
101 102 103
  Page* first_page =
      MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
  CHECK(first_page->is_valid());
104
  CHECK(allocated == requested || allocated == requested - 1);
105 106 107 108 109 110 111 112
  total_pages += allocated;

  Page* last_page = first_page;
  for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
    CHECK(MemoryAllocator::IsPageInSpace(p, &faked_space));
    last_page = p;
  }

113
  // Again, we should get n or n - 1 pages.
114 115 116
  Page* others =
      MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
  CHECK(others->is_valid());
117
  CHECK(allocated == requested || allocated == requested - 1);
118 119 120 121 122 123 124 125 126 127 128 129 130 131
  total_pages += allocated;

  MemoryAllocator::SetNextPage(last_page, others);
  int page_count = 0;
  for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
    CHECK(MemoryAllocator::IsPageInSpace(p, &faked_space));
    page_count++;
  }
  CHECK(total_pages == page_count);

  Page* second_page = first_page->next_page();
  CHECK(second_page->is_valid());

  // Freeing pages at the first chunk starting at or after the second page
132 133
  // should free the entire second chunk.  It will return the page it was passed
  // (since the second page was in the first chunk).
134
  Page* free_return = MemoryAllocator::FreePages(second_page);
135
  CHECK(free_return == second_page);
136 137 138 139 140 141 142 143 144 145 146 147 148
  MemoryAllocator::SetNextPage(first_page, free_return);

  // Freeing pages in the first chunk starting at the first page should free
  // the first chunk and return an invalid page.
  Page* invalid_page = MemoryAllocator::FreePages(first_page);
  CHECK(!invalid_page->is_valid());

  MemoryAllocator::TearDown();
}


TEST(NewSpace) {
  CHECK(Heap::ConfigureHeapDefault());
149
  CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
150

151
  NewSpace new_space;
152 153

  void* chunk =
154
      MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
155 156
  CHECK(chunk != NULL);
  Address start = RoundUp(static_cast<Address>(chunk),
157 158
                          2 * Heap::ReservedSemiSpaceSize());
  CHECK(new_space.Setup(start, 2 * Heap::ReservedSemiSpaceSize()));
159
  CHECK(new_space.HasBeenSetup());
160

161
  while (new_space.Available() >= Page::kMaxHeapObjectSize) {
162 163
    Object* obj =
        new_space.AllocateRaw(Page::kMaxHeapObjectSize)->ToObjectUnchecked();
164
    CHECK(new_space.Contains(HeapObject::cast(obj)));
165 166
  }

167
  new_space.TearDown();
168 169 170 171 172 173
  MemoryAllocator::TearDown();
}


TEST(OldSpace) {
  CHECK(Heap::ConfigureHeapDefault());
174
  CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
175

176
  OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(),
177 178
                             OLD_POINTER_SPACE,
                             NOT_EXECUTABLE);
179 180 181
  CHECK(s != NULL);

  void* chunk =
182
      MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
183 184
  CHECK(chunk != NULL);
  Address start = static_cast<Address>(chunk);
185
  size_t size = RoundUp(start, 2 * Heap::ReservedSemiSpaceSize()) - start;
186 187 188 189

  CHECK(s->Setup(start, size));

  while (s->Available() > 0) {
190
    s->AllocateRaw(Page::kMaxHeapObjectSize)->ToObjectUnchecked();
191 192 193 194 195 196 197 198 199
  }

  s->TearDown();
  delete s;
  MemoryAllocator::TearDown();
}


TEST(LargeObjectSpace) {
200
  CHECK(Heap::Setup(false));
201

202
  LargeObjectSpace* lo = Heap::lo_space();
203 204 205 206 207
  CHECK(lo != NULL);

  Map* faked_map = reinterpret_cast<Map*>(HeapObject::FromAddress(0));
  int lo_size = Page::kPageSize;

208
  Object* obj = lo->AllocateRaw(lo_size)->ToObjectUnchecked();
209 210 211 212 213 214 215 216 217 218 219 220
  CHECK(obj->IsHeapObject());

  HeapObject* ho = HeapObject::cast(obj);
  ho->set_map(faked_map);

  CHECK(lo->Contains(HeapObject::cast(obj)));

  CHECK(lo->FindObject(ho->address()) == obj);

  CHECK(lo->Contains(ho));

  while (true) {
221
    intptr_t available = lo->Available();
222 223 224
    { MaybeObject* maybe_obj = lo->AllocateRaw(lo_size);
      if (!maybe_obj->ToObject(&obj)) break;
    }
225 226 227 228 229 230
    HeapObject::cast(obj)->set_map(faked_map);
    CHECK(lo->Available() < available);
  };

  CHECK(!lo->IsEmpty());

231
  CHECK(lo->AllocateRaw(lo_size)->IsFailure());
232 233 234 235 236 237

  lo->TearDown();
  delete lo;

  MemoryAllocator::TearDown();
}