// LIVE -> DEINITING -> DEINITED -> FREED -> DEAD, with side table TEST(LongRefcountingTest, lifecycle_live_deiniting_deinited_freed_with_side_DeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; size_t deinited = 0; auto object = allocTestObject(&deinited, 1); object->CheckLifecycle = true; // Object is LIVE EXPECT_ALLOCATED(object); // RC tested elsewhere // URC load OK // URC increment OK // URC decrement OK swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRelease(object); swift_unownedCheck(object); // Remaining releases are performed during DEINITED. // WRC load can't happen // WRC increment adds side table // WRC decrement can't happen WeakReference w; swift_weakInit(&w, object); // Object is LIVE with side table void *side = w.getSideTable(); EXPECT_ALLOCATED(side); WeakReference w_deinit; swift_weakInit(&w_deinit, object); object->WeakRef = &w_deinit; // destroyed during deinit // RC increment ok // RC decrement ok swift_retain(object); swift_retain(object); swift_retain(object); swift_release(object); swift_release(object); swift_release(object); // URC load OK // URC increment OK // URC decrement OK swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRelease(object); swift_unownedCheck(object); swift_unownedRelease(object); swift_unownedCheck(object); swift_unownedRelease(object); swift_unownedCheck(object); // WRC load OK // WRC increment OK // WRC decrement OK WeakReference w2; swift_weakInit(&w2, object); HeapObject *weakValue = swift_weakLoadStrong(&w2); EXPECT_EQ(weakValue, object); swift_release(weakValue); weakValue = swift_weakLoadStrong(&w); EXPECT_EQ(weakValue, object); swift_release(weakValue); // RC == 1 // URC == 3 // WRC == 3 swift_release(object); // DEINITING is in here // Object is DEINITED // RC == 0 // URC == 2 // WRC == 3 EXPECT_EQ(1u, deinited); EXPECT_ALLOCATED(object); EXPECT_ALLOCATED(side); // RC can't happen // WRC load is nil // WRC increment can't happen // WRC decrement OK weakValue = swift_weakTakeStrong(&w2); EXPECT_EQ(0, weakValue); // URC load crashes // URC increment can't happen // URC decrement OK ASSERT_DEATH(swift_unownedCheck(object), "Attempted to read an unowned reference"); swift_unownedRelease(object); EXPECT_ALLOCATED(object); EXPECT_ALLOCATED(side); // RC == 0 // URC == 1 // WRC == 2 swift_unownedRelease(object); // Object is FREED // RC == 0 // URC == 0 // WRC == 1 EXPECT_EQ(1u, deinited); EXPECT_UNALLOCATED(object); EXPECT_ALLOCATED(side); // RC can't happen // URC can't happen // WRC load is nil // WRC increment can't happen // WRC decrement OK // RC == 0 // URC == 0 // WRC == 1 weakValue = swift_weakTakeStrong(&w); // Object is DEAD // RC == 0 // URC == 0 // WRC == 0 EXPECT_UNALLOCATED(side); EXPECT_EQ(0, weakValue); }
// LIVE -> DEINITING -> DEAD, with side table TEST(LongRefcountingTest, lifecycle_live_deiniting_with_side_DeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; size_t deinited = 0; auto object = allocTestObject(&deinited, 1); object->CheckLifecycle = true; // Object is LIVE EXPECT_ALLOCATED(object); // RC tested elsewhere // URC load OK // URC increment OK // URC decrement OK swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRelease(object); swift_unownedCheck(object); // Remaining releases are performed after the side table is allocated. // WRC load can't happen // WRC increment adds side table // WRC decrement can't happen WeakReference w; swift_weakInit(&w, object); // Object is LIVE with side table void *side = w.getSideTable(); EXPECT_ALLOCATED(side); WeakReference w_deinit; swift_weakInit(&w_deinit, object); object->WeakRef = &w_deinit; // destroyed during deinit // RC increment ok // RC decrement ok swift_retain(object); swift_retain(object); swift_retain(object); swift_release(object); swift_release(object); swift_release(object); // URC load OK // URC increment OK // URC decrement OK swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRetain(object); swift_unownedCheck(object); swift_unownedRelease(object); swift_unownedCheck(object); swift_unownedRelease(object); swift_unownedCheck(object); swift_unownedRelease(object); swift_unownedCheck(object); // ...and balancing from previously... swift_unownedRelease(object); swift_unownedCheck(object); swift_unownedRelease(object); swift_unownedCheck(object); // WRC load OK // WRC increment OK // WRC decrement OK WeakReference w2; swift_weakInit(&w2, object); HeapObject *weakValue = swift_weakTakeStrong(&w2); EXPECT_EQ(weakValue, object); swift_release(weakValue); weakValue = swift_weakTakeStrong(&w); EXPECT_EQ(weakValue, object); swift_release(weakValue); // RC == 1 // URC == 1 // WRC == 1 swift_release(object); // DEINITING is in here // Object is DEAD // RC == 0 // URC == 0 // WRC == 0 EXPECT_UNALLOCATED(side); EXPECT_UNALLOCATED(object); }