LCOV - code coverage report
Current view: top level - test/cctest/heap - test-mark-compact.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 144 146 98.6 %
Date: 2017-10-20 Functions: 10 10 100.0 %

          Line data    Source code
       1             : // Copyright 2012 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             : #ifdef __linux__
      31             : #include <errno.h>
      32             : #include <fcntl.h>
      33             : #include <sys/stat.h>
      34             : #include <sys/types.h>
      35             : #include <unistd.h>
      36             : #endif
      37             : 
      38             : #include <utility>
      39             : 
      40             : #include "src/v8.h"
      41             : 
      42             : #include "src/global-handles.h"
      43             : #include "src/heap/mark-compact-inl.h"
      44             : #include "src/heap/mark-compact.h"
      45             : #include "src/objects-inl.h"
      46             : #include "test/cctest/cctest.h"
      47             : #include "test/cctest/heap/heap-tester.h"
      48             : #include "test/cctest/heap/heap-utils.h"
      49             : 
      50             : namespace v8 {
      51             : namespace internal {
      52             : namespace heap {
      53             : 
      54       23724 : TEST(Promotion) {
      55           6 :   CcTest::InitializeVM();
      56             :   Isolate* isolate = CcTest::i_isolate();
      57             :   {
      58           6 :     v8::HandleScope sc(CcTest::isolate());
      59           6 :     Heap* heap = isolate->heap();
      60             : 
      61           6 :     heap::SealCurrentObjects(heap);
      62             : 
      63           6 :     int array_length = heap::FixedArrayLenFromSize(kMaxRegularHeapObjectSize);
      64           6 :     Handle<FixedArray> array = isolate->factory()->NewFixedArray(array_length);
      65             : 
      66             :     // Array should be in the new space.
      67           6 :     CHECK(heap->InSpace(*array, NEW_SPACE));
      68           6 :     CcTest::CollectAllGarbage();
      69           6 :     CcTest::CollectAllGarbage();
      70           6 :     CHECK(heap->InSpace(*array, OLD_SPACE));
      71             :   }
      72           6 : }
      73             : 
      74       23724 : HEAP_TEST(NoPromotion) {
      75             :   // Page promotion allows pages to be moved to old space even in the case of
      76             :   // OOM scenarios.
      77           6 :   FLAG_page_promotion = false;
      78             : 
      79           6 :   CcTest::InitializeVM();
      80             :   Isolate* isolate = CcTest::i_isolate();
      81             :   {
      82           6 :     v8::HandleScope sc(CcTest::isolate());
      83           6 :     Heap* heap = isolate->heap();
      84             : 
      85           6 :     heap::SealCurrentObjects(heap);
      86             : 
      87           6 :     int array_length = heap::FixedArrayLenFromSize(kMaxRegularHeapObjectSize);
      88           6 :     Handle<FixedArray> array = isolate->factory()->NewFixedArray(array_length);
      89             : 
      90             :     heap->set_force_oom(true);
      91             :     // Array should be in the new space.
      92           6 :     CHECK(heap->InSpace(*array, NEW_SPACE));
      93           6 :     CcTest::CollectAllGarbage();
      94           6 :     CcTest::CollectAllGarbage();
      95           6 :     CHECK(heap->InSpace(*array, NEW_SPACE));
      96             :   }
      97           6 : }
      98             : 
      99       23724 : HEAP_TEST(MarkCompactCollector) {
     100           6 :   FLAG_incremental_marking = false;
     101           6 :   FLAG_retain_maps_for_n_gc = 0;
     102           6 :   CcTest::InitializeVM();
     103           6 :   Isolate* isolate = CcTest::i_isolate();
     104           6 :   Heap* heap = CcTest::heap();
     105             :   Factory* factory = isolate->factory();
     106             : 
     107           6 :   v8::HandleScope sc(CcTest::isolate());
     108           6 :   Handle<JSGlobalObject> global(isolate->context()->global_object());
     109             : 
     110             :   // call mark-compact when heap is empty
     111           6 :   CcTest::CollectGarbage(OLD_SPACE);
     112             : 
     113             :   // keep allocating garbage in new space until it fails
     114             :   const int arraysize = 100;
     115             :   AllocationResult allocation;
     116        7482 :   do {
     117             :     allocation = heap->AllocateFixedArray(arraysize);
     118             :   } while (!allocation.IsRetry());
     119           6 :   CcTest::CollectGarbage(NEW_SPACE);
     120           6 :   heap->AllocateFixedArray(arraysize).ToObjectChecked();
     121             : 
     122             :   // keep allocating maps until it fails
     123      732708 :   do {
     124      732708 :     allocation = heap->AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     125             :   } while (!allocation.IsRetry());
     126           6 :   CcTest::CollectGarbage(MAP_SPACE);
     127           6 :   heap->AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize).ToObjectChecked();
     128             : 
     129             :   { HandleScope scope(isolate);
     130             :     // allocate a garbage
     131           6 :     Handle<String> func_name = factory->InternalizeUtf8String("theFunction");
     132           6 :     Handle<JSFunction> function = factory->NewFunction(func_name);
     133           6 :     JSReceiver::SetProperty(global, func_name, function, LanguageMode::kSloppy)
     134          12 :         .Check();
     135             : 
     136           6 :     factory->NewJSObject(function);
     137             :   }
     138             : 
     139           6 :   CcTest::CollectGarbage(OLD_SPACE);
     140             : 
     141             :   { HandleScope scope(isolate);
     142           6 :     Handle<String> func_name = factory->InternalizeUtf8String("theFunction");
     143          12 :     CHECK(Just(true) == JSReceiver::HasOwnProperty(global, func_name));
     144             :     Handle<Object> func_value =
     145          12 :         Object::GetProperty(global, func_name).ToHandleChecked();
     146           6 :     CHECK(func_value->IsJSFunction());
     147           6 :     Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
     148           6 :     Handle<JSObject> obj = factory->NewJSObject(function);
     149             : 
     150           6 :     Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
     151           6 :     JSReceiver::SetProperty(global, obj_name, obj, LanguageMode::kSloppy)
     152          12 :         .Check();
     153           6 :     Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
     154             :     Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
     155           6 :     JSReceiver::SetProperty(obj, prop_name, twenty_three, LanguageMode::kSloppy)
     156          12 :         .Check();
     157             :   }
     158             : 
     159           6 :   CcTest::CollectGarbage(OLD_SPACE);
     160             : 
     161             :   { HandleScope scope(isolate);
     162           6 :     Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
     163          12 :     CHECK(Just(true) == JSReceiver::HasOwnProperty(global, obj_name));
     164             :     Handle<Object> object =
     165          12 :         Object::GetProperty(global, obj_name).ToHandleChecked();
     166           6 :     CHECK(object->IsJSObject());
     167           6 :     Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
     168          12 :     CHECK_EQ(*Object::GetProperty(object, prop_name).ToHandleChecked(),
     169             :              Smi::FromInt(23));
     170           6 :   }
     171           6 : }
     172             : 
     173             : 
     174             : // TODO(1600): compaction of map space is temporary removed from GC.
     175             : #if 0
     176             : static Handle<Map> CreateMap(Isolate* isolate) {
     177             :   return isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     178             : }
     179             : 
     180             : 
     181             : TEST(MapCompact) {
     182             :   FLAG_max_map_space_pages = 16;
     183             :   CcTest::InitializeVM();
     184             :   Isolate* isolate = CcTest::i_isolate();
     185             :   Factory* factory = isolate->factory();
     186             : 
     187             :   {
     188             :     v8::HandleScope sc;
     189             :     // keep allocating maps while pointers are still encodable and thus
     190             :     // mark compact is permitted.
     191             :     Handle<JSObject> root = factory->NewJSObjectFromMap(CreateMap());
     192             :     do {
     193             :       Handle<Map> map = CreateMap();
     194             :       map->set_prototype(*root);
     195             :       root = factory->NewJSObjectFromMap(map);
     196             :     } while (CcTest::heap()->map_space()->MapPointersEncodable());
     197             :   }
     198             :   // Now, as we don't have any handles to just allocated maps, we should
     199             :   // be able to trigger map compaction.
     200             :   // To give an additional chance to fail, try to force compaction which
     201             :   // should be impossible right now.
     202             :   CcTest::CollectAllGarbage(Heap::kForceCompactionMask);
     203             :   // And now map pointers should be encodable again.
     204             :   CHECK(CcTest::heap()->map_space()->MapPointersEncodable());
     205             : }
     206             : #endif
     207             : 
     208             : #if defined(__has_feature)
     209             : #if __has_feature(address_sanitizer)
     210             : #define V8_WITH_ASAN 1
     211             : #endif
     212             : #endif
     213             : 
     214             : // Here is a memory use test that uses /proc, and is therefore Linux-only.  We
     215             : // do not care how much memory the simulator uses, since it is only there for
     216             : // debugging purposes. Testing with ASAN doesn't make sense, either.
     217             : #if defined(__linux__) && !defined(USE_SIMULATOR) && !defined(V8_WITH_ASAN)
     218             : 
     219             : 
     220       23808 : static uintptr_t ReadLong(char* buffer, intptr_t* position, int base) {
     221       23808 :   char* end_address = buffer + *position;
     222       23808 :   uintptr_t result = strtoul(buffer + *position, &end_address, base);
     223       23808 :   CHECK(result != ULONG_MAX || errno != ERANGE);
     224       23808 :   CHECK(end_address > buffer + *position);
     225       23808 :   *position = end_address - buffer;
     226       23808 :   return result;
     227             : }
     228             : 
     229             : 
     230             : // The memory use computed this way is not entirely accurate and depends on
     231             : // the way malloc allocates memory.  That's why the memory use may seem to
     232             : // increase even though the sum of the allocated object sizes decreases.  It
     233             : // also means that the memory use depends on the kernel and stdlib.
     234          66 : static intptr_t MemoryInUse() {
     235             :   intptr_t memory_use = 0;
     236             : 
     237             :   int fd = open("/proc/self/maps", O_RDONLY);
     238          66 :   if (fd < 0) return -1;
     239             : 
     240             :   const int kBufSize = 20000;
     241             :   char buffer[kBufSize];
     242             :   ssize_t length = read(fd, buffer, kBufSize);
     243             :   intptr_t line_start = 0;
     244          66 :   CHECK_LT(length, kBufSize);  // Make the buffer bigger.
     245          66 :   CHECK_GT(length, 0);  // We have to find some data in the file.
     246        8002 :   while (line_start < length) {
     247        7936 :     if (buffer[line_start] == '\n') {
     248        3968 :       line_start++;
     249        3968 :       continue;
     250             :     }
     251        3968 :     intptr_t position = line_start;
     252        3968 :     uintptr_t start = ReadLong(buffer, &position, 16);
     253        3968 :     CHECK_EQ(buffer[position++], '-');
     254        3968 :     uintptr_t end = ReadLong(buffer, &position, 16);
     255        3968 :     CHECK_EQ(buffer[position++], ' ');
     256        3968 :     CHECK(buffer[position] == '-' || buffer[position] == 'r');
     257        3968 :     bool read_permission = (buffer[position++] == 'r');
     258        3968 :     CHECK(buffer[position] == '-' || buffer[position] == 'w');
     259        3968 :     bool write_permission = (buffer[position++] == 'w');
     260        3968 :     CHECK(buffer[position] == '-' || buffer[position] == 'x');
     261        3968 :     bool execute_permission = (buffer[position++] == 'x');
     262        3968 :     CHECK(buffer[position] == 's' || buffer[position] == 'p');
     263        3968 :     bool private_mapping = (buffer[position++] == 'p');
     264        3968 :     CHECK_EQ(buffer[position++], ' ');
     265        3968 :     uintptr_t offset = ReadLong(buffer, &position, 16);
     266             :     USE(offset);
     267        3968 :     CHECK_EQ(buffer[position++], ' ');
     268        3968 :     uintptr_t major = ReadLong(buffer, &position, 16);
     269             :     USE(major);
     270        3968 :     CHECK_EQ(buffer[position++], ':');
     271        3968 :     uintptr_t minor = ReadLong(buffer, &position, 16);
     272             :     USE(minor);
     273        3968 :     CHECK_EQ(buffer[position++], ' ');
     274        3968 :     uintptr_t inode = ReadLong(buffer, &position, 10);
     275        3968 :     while (position < length && buffer[position] != '\n') position++;
     276        3968 :     if ((read_permission || write_permission || execute_permission) &&
     277        2321 :         private_mapping && inode == 0) {
     278        1645 :       memory_use += (end - start);
     279             :     }
     280             : 
     281             :     line_start = position;
     282             :   }
     283          66 :   close(fd);
     284          66 :   return memory_use;
     285             : }
     286             : 
     287             : 
     288          66 : intptr_t ShortLivingIsolate() {
     289             :   v8::Isolate::CreateParams create_params;
     290          66 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     291          66 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     292             :   { v8::Isolate::Scope isolate_scope(isolate);
     293          66 :     v8::Locker lock(isolate);
     294         132 :     v8::HandleScope handle_scope(isolate);
     295          66 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
     296          66 :     CHECK(!context.IsEmpty());
     297             :   }
     298          66 :   isolate->Dispose();
     299          66 :   return MemoryInUse();
     300             : }
     301             : 
     302             : 
     303       23724 : TEST(RegressJoinThreadsOnIsolateDeinit) {
     304           6 :   intptr_t size_limit = ShortLivingIsolate() * 2;
     305          66 :   for (int i = 0; i < 10; i++) {
     306          60 :     CHECK_GT(size_limit, ShortLivingIsolate());
     307             :   }
     308           6 : }
     309             : 
     310       23724 : TEST(Regress5829) {
     311           6 :   CcTest::InitializeVM();
     312             :   Isolate* isolate = CcTest::i_isolate();
     313           6 :   v8::HandleScope sc(CcTest::isolate());
     314          18 :   Heap* heap = isolate->heap();
     315           6 :   heap::SealCurrentObjects(heap);
     316             :   i::MarkCompactCollector* collector = heap->mark_compact_collector();
     317             :   i::IncrementalMarking* marking = heap->incremental_marking();
     318           6 :   if (collector->sweeping_in_progress()) {
     319           0 :     collector->EnsureSweepingCompleted();
     320             :   }
     321           6 :   CHECK(marking->IsMarking() || marking->IsStopped());
     322           6 :   if (marking->IsStopped()) {
     323             :     heap->StartIncrementalMarking(i::Heap::kNoGCFlags,
     324           6 :                                   i::GarbageCollectionReason::kTesting);
     325             :   }
     326           6 :   CHECK(marking->IsMarking());
     327             :   marking->StartBlackAllocationForTesting();
     328           6 :   Handle<FixedArray> array = isolate->factory()->NewFixedArray(10, TENURED);
     329           6 :   Address old_end = array->address() + array->Size();
     330             :   // Right trim the array without clearing the mark bits.
     331             :   array->set_length(9);
     332             :   heap->CreateFillerObjectAt(old_end - kPointerSize, kPointerSize,
     333           6 :                              ClearRecordedSlots::kNo);
     334           6 :   heap->old_space()->EmptyAllocationInfo();
     335           6 :   Page* page = Page::FromAddress(array->address());
     336             :   IncrementalMarking::MarkingState* marking_state = marking->marking_state();
     337           6 :   for (auto object_and_size :
     338          12 :        LiveObjectRange<kGreyObjects>(page, marking_state->bitmap(page))) {
     339           0 :     CHECK(!object_and_size.first->IsFiller());
     340           6 :   }
     341           6 : }
     342             : 
     343             : #endif  // __linux__ and !USE_SIMULATOR
     344             : 
     345             : }  // namespace heap
     346             : }  // namespace internal
     347       71154 : }  // namespace v8

Generated by: LCOV version 1.10