OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "platform/assert.h" |
| 6 #include "vm/globals.h" |
| 7 #include "vm/object_id_ring.h" |
| 8 #include "vm/unit_test.h" |
| 9 #include "vm/dart_api_impl.h" |
| 10 |
| 11 namespace dart { |
| 12 |
| 13 |
| 14 class ObjectIdRingTestHelper { |
| 15 public: |
| 16 static ObjectIdRing* CreateRing(Isolate* isolate, intptr_t capacity) { |
| 17 ObjectIdRing* ring = new ObjectIdRing(isolate, capacity); |
| 18 SetSmallMaxSerial(ring); |
| 19 return ring; |
| 20 } |
| 21 |
| 22 static void SetSmallMaxSerial(ObjectIdRing* ring) { |
| 23 ring->max_serial_ = ring->capacity_ * 2; |
| 24 } |
| 25 |
| 26 static void ExpectIdIsValid(ObjectIdRing* ring, intptr_t id) { |
| 27 EXPECT(ring->IsValidId(id)); |
| 28 } |
| 29 |
| 30 static void ExpectIdIsInvalid(ObjectIdRing* ring, intptr_t id) { |
| 31 EXPECT(!ring->IsValidId(id)); |
| 32 } |
| 33 }; |
| 34 |
| 35 |
| 36 // Test that serial number wrapping works. |
| 37 UNIT_TEST_CASE(ObjectIdRingSerialWrapTest) { |
| 38 ObjectIdRing* ring = ObjectIdRingTestHelper::CreateRing(NULL, 2); |
| 39 intptr_t id; |
| 40 id = ring->GetIdForObject(Object::null()); |
| 41 EXPECT_EQ(0, id); |
| 42 id = ring->GetIdForObject(Object::null()); |
| 43 EXPECT_EQ(1, id); |
| 44 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 0); |
| 45 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 1); |
| 46 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 2); |
| 47 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 3); |
| 48 id = ring->GetIdForObject(Object::null()); |
| 49 EXPECT_EQ(2, id); |
| 50 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 0); |
| 51 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 1); |
| 52 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 2); |
| 53 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 3); |
| 54 id = ring->GetIdForObject(Object::null()); |
| 55 EXPECT_EQ(3, id); |
| 56 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 0); |
| 57 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 1); |
| 58 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 2); |
| 59 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 3); |
| 60 id = ring->GetIdForObject(Object::null()); |
| 61 EXPECT_EQ(0, id); |
| 62 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 0); |
| 63 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 1); |
| 64 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 2); |
| 65 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 3); |
| 66 id = ring->GetIdForObject(Object::null()); |
| 67 EXPECT_EQ(1, id); |
| 68 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 0); |
| 69 ObjectIdRingTestHelper::ExpectIdIsValid(ring, 1); |
| 70 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 2); |
| 71 ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 3); |
| 72 } |
| 73 |
| 74 |
| 75 // Test that the ring table is updated when the scavenger moves an object. |
| 76 TEST_CASE(ObjectIdRingScavengeMoveTest) { |
| 77 const char* kScriptChars = |
| 78 "main() {\n" |
| 79 " return [1, 2, 3];\n" |
| 80 "}\n"; |
| 81 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); |
| 82 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); |
| 83 intptr_t list_length = 0; |
| 84 EXPECT_VALID(result); |
| 85 EXPECT(!Dart_IsNull(result)); |
| 86 EXPECT(Dart_IsList(result)); |
| 87 EXPECT_VALID(Dart_ListLength(result, &list_length)); |
| 88 EXPECT_EQ(3, list_length); |
| 89 Isolate* isolate = Isolate::Current(); |
| 90 Heap* heap = isolate->heap(); |
| 91 ObjectIdRing* ring = isolate->get_object_id_ring(); |
| 92 RawObject* raw_obj = Api::UnwrapHandle(result); |
| 93 // Located in new heap. |
| 94 EXPECT(raw_obj->IsNewObject()); |
| 95 EXPECT_NE(Object::null(), raw_obj); |
| 96 intptr_t raw_obj_id1 = ring->GetIdForObject(raw_obj); |
| 97 EXPECT_EQ(0, raw_obj_id1); |
| 98 intptr_t raw_obj_id2 = ring->GetIdForObject(raw_obj); |
| 99 EXPECT_EQ(1, raw_obj_id2); |
| 100 intptr_t raw_obj_id3 = ring->GetIdForObject(Object::null()); |
| 101 RawObject* raw_obj1 = ring->GetObjectForId(raw_obj_id1); |
| 102 RawObject* raw_obj2 = ring->GetObjectForId(raw_obj_id2); |
| 103 RawObject* raw_obj3 = ring->GetObjectForId(raw_obj_id3); |
| 104 EXPECT_NE(Object::null(), raw_obj1); |
| 105 EXPECT_NE(Object::null(), raw_obj2); |
| 106 EXPECT_EQ(Object::null(), raw_obj3); |
| 107 EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj1)); |
| 108 EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj2)); |
| 109 // Force a scavenge. |
| 110 heap->CollectGarbage(Heap::kNew); |
| 111 RawObject* raw_object_moved1 = ring->GetObjectForId(raw_obj_id1); |
| 112 RawObject* raw_object_moved2 = ring->GetObjectForId(raw_obj_id2); |
| 113 RawObject* raw_object_moved3 = ring->GetObjectForId(raw_obj_id3); |
| 114 EXPECT_NE(Object::null(), raw_object_moved1); |
| 115 EXPECT_NE(Object::null(), raw_object_moved2); |
| 116 EXPECT_EQ(Object::null(), raw_object_moved3); |
| 117 EXPECT_EQ(RawObject::ToAddr(raw_object_moved1), |
| 118 RawObject::ToAddr(raw_object_moved2)); |
| 119 // Test that objects have moved. |
| 120 EXPECT_NE(RawObject::ToAddr(raw_obj1), RawObject::ToAddr(raw_object_moved1)); |
| 121 EXPECT_NE(RawObject::ToAddr(raw_obj2), RawObject::ToAddr(raw_object_moved2)); |
| 122 // Test that we still point at the same list. |
| 123 Dart_Handle moved_handle = Api::NewHandle(isolate, raw_object_moved1); |
| 124 EXPECT_VALID(moved_handle); |
| 125 EXPECT(!Dart_IsNull(moved_handle)); |
| 126 EXPECT(Dart_IsList(moved_handle)); |
| 127 EXPECT_VALID(Dart_ListLength(moved_handle, &list_length)); |
| 128 EXPECT_EQ(3, list_length); |
| 129 } |
| 130 |
| 131 |
| 132 // Test that the ring table is updated with nulls when the old GC collects. |
| 133 TEST_CASE(ObjectIdRingOldGCTest) { |
| 134 const char* kScriptChars = |
| 135 "main() {\n" |
| 136 " return [1, 2, 3];\n" |
| 137 "}\n"; |
| 138 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); |
| 139 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); |
| 140 intptr_t list_length = 0; |
| 141 EXPECT_VALID(result); |
| 142 EXPECT(!Dart_IsNull(result)); |
| 143 EXPECT(Dart_IsList(result)); |
| 144 EXPECT_VALID(Dart_ListLength(result, &list_length)); |
| 145 EXPECT_EQ(3, list_length); |
| 146 Isolate* isolate = Isolate::Current(); |
| 147 Heap* heap = isolate->heap(); |
| 148 ObjectIdRing* ring = isolate->get_object_id_ring(); |
| 149 RawObject* raw_obj = Api::UnwrapHandle(result); |
| 150 // Located in new heap. |
| 151 EXPECT(raw_obj->IsNewObject()); |
| 152 EXPECT_NE(Object::null(), raw_obj); |
| 153 intptr_t raw_obj_id1 = ring->GetIdForObject(raw_obj); |
| 154 EXPECT_EQ(0, raw_obj_id1); |
| 155 intptr_t raw_obj_id2 = ring->GetIdForObject(raw_obj); |
| 156 EXPECT_EQ(1, raw_obj_id2); |
| 157 RawObject* raw_obj1 = ring->GetObjectForId(raw_obj_id1); |
| 158 RawObject* raw_obj2 = ring->GetObjectForId(raw_obj_id2); |
| 159 EXPECT_NE(Object::null(), raw_obj1); |
| 160 EXPECT_NE(Object::null(), raw_obj2); |
| 161 EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj1)); |
| 162 EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj2)); |
| 163 // Force a GC. |
| 164 heap->CollectGarbage(Heap::kOld); |
| 165 RawObject* raw_object_moved1 = ring->GetObjectForId(raw_obj_id1); |
| 166 RawObject* raw_object_moved2 = ring->GetObjectForId(raw_obj_id2); |
| 167 // Objects should now be null. |
| 168 EXPECT_EQ(Object::null(), raw_object_moved1); |
| 169 EXPECT_EQ(Object::null(), raw_object_moved2); |
| 170 } |
| 171 |
| 172 } // namespace dart |
OLD | NEW |