| OLD | NEW |
| (Empty) |
| 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 // TODO(jochen): Remove this after the setting is turned on globally. | |
| 29 #define V8_IMMINENT_DEPRECATION_WARNINGS | |
| 30 | |
| 31 #include <stdlib.h> | |
| 32 | |
| 33 #ifdef __linux__ | |
| 34 #include <errno.h> | |
| 35 #include <fcntl.h> | |
| 36 #include <sys/stat.h> | |
| 37 #include <sys/types.h> | |
| 38 #include <unistd.h> | |
| 39 #endif | |
| 40 | |
| 41 #include <utility> | |
| 42 | |
| 43 #include "src/v8.h" | |
| 44 | |
| 45 #include "src/full-codegen/full-codegen.h" | |
| 46 #include "src/global-handles.h" | |
| 47 #include "test/cctest/cctest.h" | |
| 48 #include "test/cctest/heap-tester.h" | |
| 49 | |
| 50 using namespace v8::internal; | |
| 51 using v8::Just; | |
| 52 | |
| 53 | |
| 54 TEST(MarkingDeque) { | |
| 55 CcTest::InitializeVM(); | |
| 56 int mem_size = 20 * kPointerSize; | |
| 57 byte* mem = NewArray<byte>(20*kPointerSize); | |
| 58 Address low = reinterpret_cast<Address>(mem); | |
| 59 Address high = low + mem_size; | |
| 60 MarkingDeque s; | |
| 61 s.Initialize(low, high); | |
| 62 | |
| 63 Address original_address = reinterpret_cast<Address>(&s); | |
| 64 Address current_address = original_address; | |
| 65 while (!s.IsFull()) { | |
| 66 s.Push(HeapObject::FromAddress(current_address)); | |
| 67 current_address += kPointerSize; | |
| 68 } | |
| 69 | |
| 70 while (!s.IsEmpty()) { | |
| 71 Address value = s.Pop()->address(); | |
| 72 current_address -= kPointerSize; | |
| 73 CHECK_EQ(current_address, value); | |
| 74 } | |
| 75 | |
| 76 CHECK_EQ(original_address, current_address); | |
| 77 DeleteArray(mem); | |
| 78 } | |
| 79 | |
| 80 | |
| 81 HEAP_TEST(Promotion) { | |
| 82 CcTest::InitializeVM(); | |
| 83 Heap* heap = CcTest::heap(); | |
| 84 heap->ConfigureHeap(1, 1, 1, 0); | |
| 85 | |
| 86 v8::HandleScope sc(CcTest::isolate()); | |
| 87 | |
| 88 // Allocate a fixed array in the new space. | |
| 89 int array_length = | |
| 90 (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) / | |
| 91 (4 * kPointerSize); | |
| 92 Object* obj = heap->AllocateFixedArray(array_length).ToObjectChecked(); | |
| 93 Handle<FixedArray> array(FixedArray::cast(obj)); | |
| 94 | |
| 95 // Array should be in the new space. | |
| 96 CHECK(heap->InSpace(*array, NEW_SPACE)); | |
| 97 | |
| 98 // Call mark compact GC, so array becomes an old object. | |
| 99 heap->CollectAllGarbage(); | |
| 100 heap->CollectAllGarbage(); | |
| 101 | |
| 102 // Array now sits in the old space | |
| 103 CHECK(heap->InSpace(*array, OLD_SPACE)); | |
| 104 } | |
| 105 | |
| 106 | |
| 107 HEAP_TEST(NoPromotion) { | |
| 108 CcTest::InitializeVM(); | |
| 109 Heap* heap = CcTest::heap(); | |
| 110 heap->ConfigureHeap(1, 1, 1, 0); | |
| 111 | |
| 112 v8::HandleScope sc(CcTest::isolate()); | |
| 113 | |
| 114 // Allocate a big fixed array in the new space. | |
| 115 int array_length = | |
| 116 (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) / | |
| 117 (2 * kPointerSize); | |
| 118 Object* obj = heap->AllocateFixedArray(array_length).ToObjectChecked(); | |
| 119 Handle<FixedArray> array(FixedArray::cast(obj)); | |
| 120 | |
| 121 // Array should be in the new space. | |
| 122 CHECK(heap->InSpace(*array, NEW_SPACE)); | |
| 123 | |
| 124 // Simulate a full old space to make promotion fail. | |
| 125 SimulateFullSpace(heap->old_space()); | |
| 126 | |
| 127 // Call mark compact GC, and it should pass. | |
| 128 heap->CollectGarbage(OLD_SPACE); | |
| 129 } | |
| 130 | |
| 131 | |
| 132 HEAP_TEST(MarkCompactCollector) { | |
| 133 FLAG_incremental_marking = false; | |
| 134 FLAG_retain_maps_for_n_gc = 0; | |
| 135 CcTest::InitializeVM(); | |
| 136 Isolate* isolate = CcTest::i_isolate(); | |
| 137 Heap* heap = CcTest::heap(); | |
| 138 Factory* factory = isolate->factory(); | |
| 139 | |
| 140 v8::HandleScope sc(CcTest::isolate()); | |
| 141 Handle<JSGlobalObject> global(isolate->context()->global_object()); | |
| 142 | |
| 143 // call mark-compact when heap is empty | |
| 144 heap->CollectGarbage(OLD_SPACE, "trigger 1"); | |
| 145 | |
| 146 // keep allocating garbage in new space until it fails | |
| 147 const int arraysize = 100; | |
| 148 AllocationResult allocation; | |
| 149 do { | |
| 150 allocation = heap->AllocateFixedArray(arraysize); | |
| 151 } while (!allocation.IsRetry()); | |
| 152 heap->CollectGarbage(NEW_SPACE, "trigger 2"); | |
| 153 heap->AllocateFixedArray(arraysize).ToObjectChecked(); | |
| 154 | |
| 155 // keep allocating maps until it fails | |
| 156 do { | |
| 157 allocation = heap->AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); | |
| 158 } while (!allocation.IsRetry()); | |
| 159 heap->CollectGarbage(MAP_SPACE, "trigger 3"); | |
| 160 heap->AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize).ToObjectChecked(); | |
| 161 | |
| 162 { HandleScope scope(isolate); | |
| 163 // allocate a garbage | |
| 164 Handle<String> func_name = factory->InternalizeUtf8String("theFunction"); | |
| 165 Handle<JSFunction> function = factory->NewFunction(func_name); | |
| 166 JSReceiver::SetProperty(global, func_name, function, SLOPPY).Check(); | |
| 167 | |
| 168 factory->NewJSObject(function); | |
| 169 } | |
| 170 | |
| 171 heap->CollectGarbage(OLD_SPACE, "trigger 4"); | |
| 172 | |
| 173 { HandleScope scope(isolate); | |
| 174 Handle<String> func_name = factory->InternalizeUtf8String("theFunction"); | |
| 175 CHECK(Just(true) == JSReceiver::HasOwnProperty(global, func_name)); | |
| 176 Handle<Object> func_value = | |
| 177 Object::GetProperty(global, func_name).ToHandleChecked(); | |
| 178 CHECK(func_value->IsJSFunction()); | |
| 179 Handle<JSFunction> function = Handle<JSFunction>::cast(func_value); | |
| 180 Handle<JSObject> obj = factory->NewJSObject(function); | |
| 181 | |
| 182 Handle<String> obj_name = factory->InternalizeUtf8String("theObject"); | |
| 183 JSReceiver::SetProperty(global, obj_name, obj, SLOPPY).Check(); | |
| 184 Handle<String> prop_name = factory->InternalizeUtf8String("theSlot"); | |
| 185 Handle<Smi> twenty_three(Smi::FromInt(23), isolate); | |
| 186 JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); | |
| 187 } | |
| 188 | |
| 189 heap->CollectGarbage(OLD_SPACE, "trigger 5"); | |
| 190 | |
| 191 { HandleScope scope(isolate); | |
| 192 Handle<String> obj_name = factory->InternalizeUtf8String("theObject"); | |
| 193 CHECK(Just(true) == JSReceiver::HasOwnProperty(global, obj_name)); | |
| 194 Handle<Object> object = | |
| 195 Object::GetProperty(global, obj_name).ToHandleChecked(); | |
| 196 CHECK(object->IsJSObject()); | |
| 197 Handle<String> prop_name = factory->InternalizeUtf8String("theSlot"); | |
| 198 CHECK_EQ(*Object::GetProperty(object, prop_name).ToHandleChecked(), | |
| 199 Smi::FromInt(23)); | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 | |
| 204 // TODO(1600): compaction of map space is temporary removed from GC. | |
| 205 #if 0 | |
| 206 static Handle<Map> CreateMap(Isolate* isolate) { | |
| 207 return isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); | |
| 208 } | |
| 209 | |
| 210 | |
| 211 TEST(MapCompact) { | |
| 212 FLAG_max_map_space_pages = 16; | |
| 213 CcTest::InitializeVM(); | |
| 214 Isolate* isolate = CcTest::i_isolate(); | |
| 215 Factory* factory = isolate->factory(); | |
| 216 | |
| 217 { | |
| 218 v8::HandleScope sc; | |
| 219 // keep allocating maps while pointers are still encodable and thus | |
| 220 // mark compact is permitted. | |
| 221 Handle<JSObject> root = factory->NewJSObjectFromMap(CreateMap()); | |
| 222 do { | |
| 223 Handle<Map> map = CreateMap(); | |
| 224 map->set_prototype(*root); | |
| 225 root = factory->NewJSObjectFromMap(map); | |
| 226 } while (CcTest::heap()->map_space()->MapPointersEncodable()); | |
| 227 } | |
| 228 // Now, as we don't have any handles to just allocated maps, we should | |
| 229 // be able to trigger map compaction. | |
| 230 // To give an additional chance to fail, try to force compaction which | |
| 231 // should be impossible right now. | |
| 232 CcTest::heap()->CollectAllGarbage(Heap::kForceCompactionMask); | |
| 233 // And now map pointers should be encodable again. | |
| 234 CHECK(CcTest::heap()->map_space()->MapPointersEncodable()); | |
| 235 } | |
| 236 #endif | |
| 237 | |
| 238 | |
| 239 static int NumberOfWeakCalls = 0; | |
| 240 static void WeakPointerCallback( | |
| 241 const v8::WeakCallbackData<v8::Value, void>& data) { | |
| 242 std::pair<v8::Persistent<v8::Value>*, int>* p = | |
| 243 reinterpret_cast<std::pair<v8::Persistent<v8::Value>*, int>*>( | |
| 244 data.GetParameter()); | |
| 245 CHECK_EQ(1234, p->second); | |
| 246 NumberOfWeakCalls++; | |
| 247 p->first->Reset(); | |
| 248 } | |
| 249 | |
| 250 | |
| 251 HEAP_TEST(ObjectGroups) { | |
| 252 FLAG_incremental_marking = false; | |
| 253 CcTest::InitializeVM(); | |
| 254 GlobalHandles* global_handles = CcTest::i_isolate()->global_handles(); | |
| 255 Heap* heap = CcTest::heap(); | |
| 256 NumberOfWeakCalls = 0; | |
| 257 v8::HandleScope handle_scope(CcTest::isolate()); | |
| 258 | |
| 259 Handle<Object> g1s1 = | |
| 260 global_handles->Create(heap->AllocateFixedArray(1).ToObjectChecked()); | |
| 261 Handle<Object> g1s2 = | |
| 262 global_handles->Create(heap->AllocateFixedArray(1).ToObjectChecked()); | |
| 263 Handle<Object> g1c1 = | |
| 264 global_handles->Create(heap->AllocateFixedArray(1).ToObjectChecked()); | |
| 265 std::pair<Handle<Object>*, int> g1s1_and_id(&g1s1, 1234); | |
| 266 GlobalHandles::MakeWeak(g1s1.location(), | |
| 267 reinterpret_cast<void*>(&g1s1_and_id), | |
| 268 &WeakPointerCallback); | |
| 269 std::pair<Handle<Object>*, int> g1s2_and_id(&g1s2, 1234); | |
| 270 GlobalHandles::MakeWeak(g1s2.location(), | |
| 271 reinterpret_cast<void*>(&g1s2_and_id), | |
| 272 &WeakPointerCallback); | |
| 273 std::pair<Handle<Object>*, int> g1c1_and_id(&g1c1, 1234); | |
| 274 GlobalHandles::MakeWeak(g1c1.location(), | |
| 275 reinterpret_cast<void*>(&g1c1_and_id), | |
| 276 &WeakPointerCallback); | |
| 277 | |
| 278 Handle<Object> g2s1 = | |
| 279 global_handles->Create(heap->AllocateFixedArray(1).ToObjectChecked()); | |
| 280 Handle<Object> g2s2 = | |
| 281 global_handles->Create(heap->AllocateFixedArray(1).ToObjectChecked()); | |
| 282 Handle<Object> g2c1 = | |
| 283 global_handles->Create(heap->AllocateFixedArray(1).ToObjectChecked()); | |
| 284 std::pair<Handle<Object>*, int> g2s1_and_id(&g2s1, 1234); | |
| 285 GlobalHandles::MakeWeak(g2s1.location(), | |
| 286 reinterpret_cast<void*>(&g2s1_and_id), | |
| 287 &WeakPointerCallback); | |
| 288 std::pair<Handle<Object>*, int> g2s2_and_id(&g2s2, 1234); | |
| 289 GlobalHandles::MakeWeak(g2s2.location(), | |
| 290 reinterpret_cast<void*>(&g2s2_and_id), | |
| 291 &WeakPointerCallback); | |
| 292 std::pair<Handle<Object>*, int> g2c1_and_id(&g2c1, 1234); | |
| 293 GlobalHandles::MakeWeak(g2c1.location(), | |
| 294 reinterpret_cast<void*>(&g2c1_and_id), | |
| 295 &WeakPointerCallback); | |
| 296 | |
| 297 Handle<Object> root = global_handles->Create(*g1s1); // make a root. | |
| 298 | |
| 299 // Connect group 1 and 2, make a cycle. | |
| 300 Handle<FixedArray>::cast(g1s2)->set(0, *g2s2); | |
| 301 Handle<FixedArray>::cast(g2s1)->set(0, *g1s1); | |
| 302 | |
| 303 { | |
| 304 Object** g1_objects[] = { g1s1.location(), g1s2.location() }; | |
| 305 Object** g2_objects[] = { g2s1.location(), g2s2.location() }; | |
| 306 global_handles->AddObjectGroup(g1_objects, 2, NULL); | |
| 307 global_handles->SetReference(Handle<HeapObject>::cast(g1s1).location(), | |
| 308 g1c1.location()); | |
| 309 global_handles->AddObjectGroup(g2_objects, 2, NULL); | |
| 310 global_handles->SetReference(Handle<HeapObject>::cast(g2s1).location(), | |
| 311 g2c1.location()); | |
| 312 } | |
| 313 // Do a full GC | |
| 314 heap->CollectGarbage(OLD_SPACE); | |
| 315 | |
| 316 // All object should be alive. | |
| 317 CHECK_EQ(0, NumberOfWeakCalls); | |
| 318 | |
| 319 // Weaken the root. | |
| 320 std::pair<Handle<Object>*, int> root_and_id(&root, 1234); | |
| 321 GlobalHandles::MakeWeak(root.location(), | |
| 322 reinterpret_cast<void*>(&root_and_id), | |
| 323 &WeakPointerCallback); | |
| 324 // But make children strong roots---all the objects (except for children) | |
| 325 // should be collectable now. | |
| 326 global_handles->ClearWeakness(g1c1.location()); | |
| 327 global_handles->ClearWeakness(g2c1.location()); | |
| 328 | |
| 329 // Groups are deleted, rebuild groups. | |
| 330 { | |
| 331 Object** g1_objects[] = { g1s1.location(), g1s2.location() }; | |
| 332 Object** g2_objects[] = { g2s1.location(), g2s2.location() }; | |
| 333 global_handles->AddObjectGroup(g1_objects, 2, NULL); | |
| 334 global_handles->SetReference(Handle<HeapObject>::cast(g1s1).location(), | |
| 335 g1c1.location()); | |
| 336 global_handles->AddObjectGroup(g2_objects, 2, NULL); | |
| 337 global_handles->SetReference(Handle<HeapObject>::cast(g2s1).location(), | |
| 338 g2c1.location()); | |
| 339 } | |
| 340 | |
| 341 heap->CollectGarbage(OLD_SPACE); | |
| 342 | |
| 343 // All objects should be gone. 5 global handles in total. | |
| 344 CHECK_EQ(5, NumberOfWeakCalls); | |
| 345 | |
| 346 // And now make children weak again and collect them. | |
| 347 GlobalHandles::MakeWeak(g1c1.location(), | |
| 348 reinterpret_cast<void*>(&g1c1_and_id), | |
| 349 &WeakPointerCallback); | |
| 350 GlobalHandles::MakeWeak(g2c1.location(), | |
| 351 reinterpret_cast<void*>(&g2c1_and_id), | |
| 352 &WeakPointerCallback); | |
| 353 | |
| 354 heap->CollectGarbage(OLD_SPACE); | |
| 355 CHECK_EQ(7, NumberOfWeakCalls); | |
| 356 } | |
| 357 | |
| 358 | |
| 359 class TestRetainedObjectInfo : public v8::RetainedObjectInfo { | |
| 360 public: | |
| 361 TestRetainedObjectInfo() : has_been_disposed_(false) {} | |
| 362 | |
| 363 bool has_been_disposed() { return has_been_disposed_; } | |
| 364 | |
| 365 virtual void Dispose() { | |
| 366 CHECK(!has_been_disposed_); | |
| 367 has_been_disposed_ = true; | |
| 368 } | |
| 369 | |
| 370 virtual bool IsEquivalent(v8::RetainedObjectInfo* other) { | |
| 371 return other == this; | |
| 372 } | |
| 373 | |
| 374 virtual intptr_t GetHash() { return 0; } | |
| 375 | |
| 376 virtual const char* GetLabel() { return "whatever"; } | |
| 377 | |
| 378 private: | |
| 379 bool has_been_disposed_; | |
| 380 }; | |
| 381 | |
| 382 | |
| 383 TEST(EmptyObjectGroups) { | |
| 384 CcTest::InitializeVM(); | |
| 385 GlobalHandles* global_handles = CcTest::i_isolate()->global_handles(); | |
| 386 | |
| 387 v8::HandleScope handle_scope(CcTest::isolate()); | |
| 388 | |
| 389 TestRetainedObjectInfo info; | |
| 390 global_handles->AddObjectGroup(NULL, 0, &info); | |
| 391 CHECK(info.has_been_disposed()); | |
| 392 } | |
| 393 | |
| 394 | |
| 395 #if defined(__has_feature) | |
| 396 #if __has_feature(address_sanitizer) | |
| 397 #define V8_WITH_ASAN 1 | |
| 398 #endif | |
| 399 #endif | |
| 400 | |
| 401 | |
| 402 // Here is a memory use test that uses /proc, and is therefore Linux-only. We | |
| 403 // do not care how much memory the simulator uses, since it is only there for | |
| 404 // debugging purposes. Testing with ASAN doesn't make sense, either. | |
| 405 #if defined(__linux__) && !defined(USE_SIMULATOR) && !defined(V8_WITH_ASAN) | |
| 406 | |
| 407 | |
| 408 static uintptr_t ReadLong(char* buffer, intptr_t* position, int base) { | |
| 409 char* end_address = buffer + *position; | |
| 410 uintptr_t result = strtoul(buffer + *position, &end_address, base); | |
| 411 CHECK(result != ULONG_MAX || errno != ERANGE); | |
| 412 CHECK(end_address > buffer + *position); | |
| 413 *position = end_address - buffer; | |
| 414 return result; | |
| 415 } | |
| 416 | |
| 417 | |
| 418 // The memory use computed this way is not entirely accurate and depends on | |
| 419 // the way malloc allocates memory. That's why the memory use may seem to | |
| 420 // increase even though the sum of the allocated object sizes decreases. It | |
| 421 // also means that the memory use depends on the kernel and stdlib. | |
| 422 static intptr_t MemoryInUse() { | |
| 423 intptr_t memory_use = 0; | |
| 424 | |
| 425 int fd = open("/proc/self/maps", O_RDONLY); | |
| 426 if (fd < 0) return -1; | |
| 427 | |
| 428 const int kBufSize = 10000; | |
| 429 char buffer[kBufSize]; | |
| 430 ssize_t length = read(fd, buffer, kBufSize); | |
| 431 intptr_t line_start = 0; | |
| 432 CHECK_LT(length, kBufSize); // Make the buffer bigger. | |
| 433 CHECK_GT(length, 0); // We have to find some data in the file. | |
| 434 while (line_start < length) { | |
| 435 if (buffer[line_start] == '\n') { | |
| 436 line_start++; | |
| 437 continue; | |
| 438 } | |
| 439 intptr_t position = line_start; | |
| 440 uintptr_t start = ReadLong(buffer, &position, 16); | |
| 441 CHECK_EQ(buffer[position++], '-'); | |
| 442 uintptr_t end = ReadLong(buffer, &position, 16); | |
| 443 CHECK_EQ(buffer[position++], ' '); | |
| 444 CHECK(buffer[position] == '-' || buffer[position] == 'r'); | |
| 445 bool read_permission = (buffer[position++] == 'r'); | |
| 446 CHECK(buffer[position] == '-' || buffer[position] == 'w'); | |
| 447 bool write_permission = (buffer[position++] == 'w'); | |
| 448 CHECK(buffer[position] == '-' || buffer[position] == 'x'); | |
| 449 bool execute_permission = (buffer[position++] == 'x'); | |
| 450 CHECK(buffer[position] == 's' || buffer[position] == 'p'); | |
| 451 bool private_mapping = (buffer[position++] == 'p'); | |
| 452 CHECK_EQ(buffer[position++], ' '); | |
| 453 uintptr_t offset = ReadLong(buffer, &position, 16); | |
| 454 USE(offset); | |
| 455 CHECK_EQ(buffer[position++], ' '); | |
| 456 uintptr_t major = ReadLong(buffer, &position, 16); | |
| 457 USE(major); | |
| 458 CHECK_EQ(buffer[position++], ':'); | |
| 459 uintptr_t minor = ReadLong(buffer, &position, 16); | |
| 460 USE(minor); | |
| 461 CHECK_EQ(buffer[position++], ' '); | |
| 462 uintptr_t inode = ReadLong(buffer, &position, 10); | |
| 463 while (position < length && buffer[position] != '\n') position++; | |
| 464 if ((read_permission || write_permission || execute_permission) && | |
| 465 private_mapping && inode == 0) { | |
| 466 memory_use += (end - start); | |
| 467 } | |
| 468 | |
| 469 line_start = position; | |
| 470 } | |
| 471 close(fd); | |
| 472 return memory_use; | |
| 473 } | |
| 474 | |
| 475 | |
| 476 intptr_t ShortLivingIsolate() { | |
| 477 v8::Isolate::CreateParams create_params; | |
| 478 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); | |
| 479 v8::Isolate* isolate = v8::Isolate::New(create_params); | |
| 480 { v8::Isolate::Scope isolate_scope(isolate); | |
| 481 v8::Locker lock(isolate); | |
| 482 v8::HandleScope handle_scope(isolate); | |
| 483 v8::Local<v8::Context> context = v8::Context::New(isolate); | |
| 484 CHECK(!context.IsEmpty()); | |
| 485 } | |
| 486 isolate->Dispose(); | |
| 487 return MemoryInUse(); | |
| 488 } | |
| 489 | |
| 490 | |
| 491 TEST(RegressJoinThreadsOnIsolateDeinit) { | |
| 492 intptr_t size_limit = ShortLivingIsolate() * 2; | |
| 493 for (int i = 0; i < 10; i++) { | |
| 494 CHECK_GT(size_limit, ShortLivingIsolate()); | |
| 495 } | |
| 496 } | |
| 497 | |
| 498 #endif // __linux__ and !USE_SIMULATOR | |
| OLD | NEW |