Flutter Engine
The Flutter Engine
object_id_ring_test.cc
Go to the documentation of this file.
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 "vm/object_id_ring.h"
6#include "platform/assert.h"
7#include "vm/dart_api_impl.h"
8#include "vm/dart_api_state.h"
9#include "vm/globals.h"
10#include "vm/symbols.h"
11#include "vm/unit_test.h"
12
13namespace dart {
14
15#ifndef PRODUCT
16
18 public:
20 int32_t capacity,
21 int32_t max_serial) {
22 ring->SetCapacityAndMaxSerial(capacity, max_serial);
23 }
24
25 static void ExpectIdIsValid(ObjectIdRing* ring, intptr_t id) {
26 EXPECT(ring->IsValidId(id));
27 }
28
29 static void ExpectIdIsInvalid(ObjectIdRing* ring, intptr_t id) {
30 EXPECT(!ring->IsValidId(id));
31 }
32
33 static void ExpectIndexId(ObjectIdRing* ring, intptr_t index, intptr_t id) {
34 EXPECT_EQ(id, ring->IdOfIndex(index));
35 }
36
37 static void ExpectInvalidIndex(ObjectIdRing* ring, intptr_t index) {
38 EXPECT_EQ(-1, ring->IdOfIndex(index));
39 }
40
41 static ObjectPtr MakeString(const char* s) {
43 }
44
45 static void ExpectString(ObjectPtr obj, const char* s) {
46 String& str = String::Handle();
47 str ^= obj;
48 EXPECT(str.Equals(s));
49 }
50};
51
52// Test that serial number wrapping works.
53ISOLATE_UNIT_TEST_CASE(ObjectIdRingSerialWrapTest) {
54 Isolate* isolate = Isolate::Current();
55 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
57 intptr_t id;
60 EXPECT_EQ(0, id);
64 EXPECT_EQ(1, id);
67 // Test that id 1 gives us the "1" string.
69 EXPECT_EQ(ObjectIdRing::kValid, kind);
76 // We have wrapped, index 0 is being reused.
78 EXPECT_EQ(2, id);
81 // Index 0 has id 2.
84 // Index 1 has id 1.
88 EXPECT_EQ(3, id);
89 // Index 0 has id 2.
91 // Index 1 has id 3.
98 EXPECT_EQ(0, id);
99 // Index 0 has id 0.
101 // Index 1 has id 3.
104 EXPECT_EQ(ObjectIdRing::kValid, kind);
110 EXPECT_EQ(1, id);
111 // Index 0 has id 0.
113 // Index 1 has id 1.
116 EXPECT_EQ(ObjectIdRing::kValid, kind);
121}
122
123// Test that the ring table is updated when the scavenger moves an object.
124TEST_CASE(ObjectIdRingScavengeMoveTest) {
125 const char* kScriptChars =
126 "main() {\n"
127 " return [1, 2, 3];\n"
128 "}\n";
129 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
130 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
131 Dart_Handle moved_handle;
132 intptr_t list_length = 0;
136 EXPECT_VALID(Dart_ListLength(result, &list_length));
137 EXPECT_EQ(3, list_length);
138
139 Isolate* isolate = thread->isolate();
140 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
142
143 {
144 TransitionNativeToVM to_vm(thread);
146 // Located in new heap.
147 EXPECT(raw_obj->IsNewObject());
148 EXPECT_NE(Object::null(), raw_obj);
149 intptr_t raw_obj_id1 = ring->GetIdForObject(raw_obj);
150 EXPECT_EQ(0, raw_obj_id1);
151 // Get id 0 again.
152 EXPECT_EQ(raw_obj_id1,
153 ring->GetIdForObject(raw_obj, ObjectIdRing::kReuseId));
154 // Add to ring a second time.
155 intptr_t raw_obj_id2 = ring->GetIdForObject(raw_obj);
156 EXPECT_EQ(1, raw_obj_id2);
157 // Get id 0 again.
158 EXPECT_EQ(raw_obj_id1,
159 ring->GetIdForObject(raw_obj, ObjectIdRing::kReuseId));
160 ObjectPtr raw_obj1 = ring->GetObjectForId(raw_obj_id1, &kind);
161 EXPECT_EQ(ObjectIdRing::kValid, kind);
162 ObjectPtr raw_obj2 = ring->GetObjectForId(raw_obj_id2, &kind);
163 EXPECT_EQ(ObjectIdRing::kValid, kind);
164 EXPECT_NE(Object::null(), raw_obj1);
165 EXPECT_NE(Object::null(), raw_obj2);
166 EXPECT_EQ(UntaggedObject::ToAddr(raw_obj),
167 UntaggedObject::ToAddr(raw_obj1));
168 EXPECT_EQ(UntaggedObject::ToAddr(raw_obj),
169 UntaggedObject::ToAddr(raw_obj2));
170 // Force a scavenge.
171 GCTestHelper::CollectNewSpace();
172 ObjectPtr raw_object_moved1 = ring->GetObjectForId(raw_obj_id1, &kind);
173 EXPECT_EQ(ObjectIdRing::kValid, kind);
174 ObjectPtr raw_object_moved2 = ring->GetObjectForId(raw_obj_id2, &kind);
175 EXPECT_EQ(ObjectIdRing::kValid, kind);
176 EXPECT_NE(Object::null(), raw_object_moved1);
177 EXPECT_NE(Object::null(), raw_object_moved2);
178 EXPECT_EQ(UntaggedObject::ToAddr(raw_object_moved1),
179 UntaggedObject::ToAddr(raw_object_moved2));
180 // Test that objects have moved.
181 EXPECT_NE(UntaggedObject::ToAddr(raw_obj1),
182 UntaggedObject::ToAddr(raw_object_moved1));
183 EXPECT_NE(UntaggedObject::ToAddr(raw_obj2),
184 UntaggedObject::ToAddr(raw_object_moved2));
185 // Test that we still point at the same list.
186 moved_handle = Api::NewHandle(thread, raw_object_moved1);
187 // Test id reuse.
188 EXPECT_EQ(raw_obj_id1,
189 ring->GetIdForObject(raw_object_moved1, ObjectIdRing::kReuseId));
190 }
191 EXPECT_VALID(moved_handle);
192 EXPECT(!Dart_IsNull(moved_handle));
193 EXPECT(Dart_IsList(moved_handle));
194 EXPECT_VALID(Dart_ListLength(moved_handle, &list_length));
195 EXPECT_EQ(3, list_length);
196}
197
198// Test that the ring table is updated when major GC runs.
199ISOLATE_UNIT_TEST_CASE(ObjectIdRingOldGCTest) {
200 Isolate* isolate = thread->isolate();
201 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
202
204 intptr_t raw_obj_id1 = -1;
205 intptr_t raw_obj_id2 = -1;
206 {
207 HandleScope handle_scope(thread);
208 const String& str = String::Handle(String::New("old", Heap::kOld));
209 EXPECT(!str.IsNull());
210 EXPECT_EQ(3, str.Length());
211
212 ObjectPtr raw_obj = Object::RawCast(str.ptr());
213 // Verify that it is located in old heap.
214 EXPECT(raw_obj->IsOldObject());
215 EXPECT_NE(Object::null(), raw_obj);
216 raw_obj_id1 = ring->GetIdForObject(raw_obj);
217 EXPECT_EQ(0, raw_obj_id1);
218 raw_obj_id2 = ring->GetIdForObject(raw_obj);
219 EXPECT_EQ(1, raw_obj_id2);
220 ObjectPtr raw_obj1 = ring->GetObjectForId(raw_obj_id1, &kind);
221 EXPECT_EQ(ObjectIdRing::kValid, kind);
222 ObjectPtr raw_obj2 = ring->GetObjectForId(raw_obj_id2, &kind);
223 EXPECT_EQ(ObjectIdRing::kValid, kind);
224 EXPECT_NE(Object::null(), raw_obj1);
225 EXPECT_NE(Object::null(), raw_obj2);
226 EXPECT_EQ(UntaggedObject::ToAddr(raw_obj),
227 UntaggedObject::ToAddr(raw_obj1));
228 EXPECT_EQ(UntaggedObject::ToAddr(raw_obj),
229 UntaggedObject::ToAddr(raw_obj2));
230 // Exit scope. Freeing String handle.
231 }
232 // Force a GC. No other reference to the old string exists, but the service id
233 // should keep it alive.
234 GCTestHelper::CollectOldSpace();
235 ObjectPtr raw_object_moved1 = ring->GetObjectForId(raw_obj_id1, &kind);
236 EXPECT_EQ(ObjectIdRing::kValid, kind);
237 EXPECT(raw_object_moved1->IsOneByteString());
238 ObjectPtr raw_object_moved2 = ring->GetObjectForId(raw_obj_id2, &kind);
239 EXPECT_EQ(ObjectIdRing::kValid, kind);
240 EXPECT(raw_object_moved2->IsOneByteString());
241 EXPECT_EQ(raw_object_moved1, raw_object_moved2);
242}
243
244// Test that the ring table correctly reports an entry as expired when it is
245// overridden by new entries.
246ISOLATE_UNIT_TEST_CASE(ObjectIdRingExpiredEntryTest) {
247 Isolate* isolate = Isolate::Current();
248 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
249
250 // Insert an object and check we can look it up.
251 String& obj = String::Handle(String::New("I will expire"));
252 intptr_t obj_id = ring->GetIdForObject(obj.ptr());
254 ObjectPtr obj_lookup = ring->GetObjectForId(obj_id, &kind);
255 EXPECT_EQ(ObjectIdRing::kValid, kind);
256 EXPECT_EQ(obj.ptr(), obj_lookup);
257
258 // Insert as many new objects as the ring size to bump out our first entry.
259 Object& new_obj = Object::Handle();
260 for (intptr_t i = 0; i < ObjectIdRing::kDefaultCapacity; i++) {
261 new_obj = String::New("Bump");
262 intptr_t new_obj_id = ring->GetIdForObject(new_obj.ptr());
264 ObjectPtr new_obj_lookup = ring->GetObjectForId(new_obj_id, &kind);
265 EXPECT_EQ(ObjectIdRing::kValid, kind);
266 EXPECT_EQ(new_obj.ptr(), new_obj_lookup);
267 }
268
269 // Check our first entry reports it has expired.
270 obj_lookup = ring->GetObjectForId(obj_id, &kind);
271 EXPECT_EQ(ObjectIdRing::kExpired, kind);
272 EXPECT_NE(obj.ptr(), obj_lookup);
273 EXPECT_EQ(Object::null(), obj_lookup);
274}
275
276#endif // !PRODUCT
277
278} // namespace dart
#define EXPECT(type, expectedAlignment, expectedSize)
static Dart_Handle NewHandle(Thread *thread, ObjectPtr raw)
static ObjectPtr UnwrapHandle(Dart_Handle object)
@ kOld
Definition: heap.h:39
static Isolate * Current()
Definition: isolate.h:986
ObjectIdRing * EnsureObjectIdRing()
Definition: isolate.cc:3014
static void ExpectIndexId(ObjectIdRing *ring, intptr_t index, intptr_t id)
static ObjectPtr MakeString(const char *s)
static void ExpectIdIsValid(ObjectIdRing *ring, intptr_t id)
static void ExpectIdIsInvalid(ObjectIdRing *ring, intptr_t id)
static void ExpectString(ObjectPtr obj, const char *s)
static void SetCapacityAndMaxSerial(ObjectIdRing *ring, int32_t capacity, int32_t max_serial)
static void ExpectInvalidIndex(ObjectIdRing *ring, intptr_t index)
static constexpr int32_t kDefaultCapacity
ObjectPtr GetObjectForId(int32_t id, LookupResult *kind)
int32_t GetIdForObject(ObjectPtr raw_obj, IdPolicy policy=kAllocateId)
static ObjectPtr null()
Definition: object.h:433
ObjectPtr ptr() const
Definition: object.h:332
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition: object.h:325
intptr_t Length() const
Definition: object.h:10210
bool Equals(const String &str) const
Definition: object.h:13337
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
static StringPtr New(Thread *thread, const char *cstr)
Definition: symbols.h:723
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition: unit_test.cc:436
static Thread * Current()
Definition: thread.h:362
static uword ToAddr(const UntaggedObject *raw_obj)
Definition: raw_object.h:522
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
struct MyStruct s
GAsyncResult * result
Definition: dart_vm.cc:33
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
TEST_CASE(DirectoryCurrent)
Dart_Handle NewString(const char *str)
DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t *len)
DART_EXPORT bool Dart_IsList(Dart_Handle object)
DART_EXPORT bool Dart_IsNull(Dart_Handle object)
const uintptr_t id
#define EXPECT_VALID(handle)
Definition: unit_test.h:643