//===- swift/unittests/runtime/weak.mm - Weak-pointer tests ---------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include #include #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" #include "gtest/gtest.h" using namespace swift; // Declare some Objective-C stuff. extern "C" void objc_release(id); static unsigned DestroyedObjCCount = 0; /// A trivial class that increments DestroyedObjCCount when deallocated. @interface ObjCClass : NSObject @end @implementation ObjCClass - (void) dealloc { DestroyedObjCCount++; [super dealloc]; } @end static HeapObject *make_objc_object() { return (HeapObject*) [ObjCClass new]; } // Make a Native Swift object by calling a Swift function. // make_swift_object is defined in TestHelpers.swift as part of StdlibUnittest. extern "C" HeapObject *make_swift_object(); static void unknown_release(void *value) { objc_release((id) value); } TEST(WeakTest, preconditions) { swift_release(make_swift_object()); unknown_release(make_objc_object()); } TEST(WeakTest, simple_swift) { HeapObject *o1 = make_swift_object(); HeapObject *o2 = make_swift_object(); ASSERT_NE(o1, o2); ASSERT_NE(o1, nullptr); ASSERT_NE(o2, nullptr); WeakReference ref1; swift_weakInit(&ref1, o1); HeapObject *tmp = swift_weakLoadStrong(&ref1); ASSERT_EQ(tmp, o1); swift_release(tmp); tmp = swift_weakLoadStrong(&ref1); ASSERT_EQ(o1, tmp); swift_release(tmp); swift_weakAssign(&ref1, o2); tmp = swift_weakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); swift_release(tmp); tmp = swift_weakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); swift_release(tmp); swift_release(o1); tmp = swift_weakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); swift_release(tmp); swift_release(o2); tmp = swift_weakLoadStrong(&ref1); ASSERT_EQ(nullptr, tmp); swift_release(tmp); swift_weakDestroy(&ref1); } TEST(WeakTest, simple_objc) { void *o1 = make_objc_object(); void *o2 = make_objc_object(); ASSERT_NE(o1, o2); ASSERT_NE(o1, nullptr); ASSERT_NE(o2, nullptr); DestroyedObjCCount = 0; WeakReference ref1; swift_unknownWeakInit(&ref1, o1); void *tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(tmp, o1); unknown_release(tmp); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o1, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); swift_unknownWeakAssign(&ref1, o2); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); unknown_release(o1); ASSERT_EQ(1U, DestroyedObjCCount); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); ASSERT_EQ(1U, DestroyedObjCCount); unknown_release(o2); ASSERT_EQ(2U, DestroyedObjCCount); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(nullptr, tmp); unknown_release(tmp); ASSERT_EQ(2U, DestroyedObjCCount); swift_unknownWeakDestroy(&ref1); } TEST(WeakTest, simple_swift_as_unknown) { void *o1 = make_swift_object(); void *o2 = make_swift_object(); ASSERT_NE(o1, o2); ASSERT_NE(o1, nullptr); ASSERT_NE(o2, nullptr); WeakReference ref1; swift_unknownWeakInit(&ref1, o1); void *tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(tmp, o1); unknown_release(tmp); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o1, tmp); unknown_release(tmp); swift_unknownWeakAssign(&ref1, o2); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); unknown_release(o1); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); unknown_release(o2); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(nullptr, tmp); unknown_release(tmp); swift_unknownWeakDestroy(&ref1); } TEST(WeakTest, simple_swift_and_objc) { void *o1 = make_swift_object(); void *o2 = make_objc_object(); ASSERT_NE(o1, o2); ASSERT_NE(o1, nullptr); ASSERT_NE(o2, nullptr); DestroyedObjCCount = 0; WeakReference ref1; swift_unknownWeakInit(&ref1, o1); void *tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(tmp, o1); unknown_release(tmp); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o1, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); swift_unknownWeakAssign(&ref1, o2); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); unknown_release(o1); ASSERT_EQ(0U, DestroyedObjCCount); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); unknown_release(o2); ASSERT_EQ(1U, DestroyedObjCCount); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(nullptr, tmp); unknown_release(tmp); ASSERT_EQ(1U, DestroyedObjCCount); swift_unknownWeakDestroy(&ref1); } TEST(WeakTest, simple_objc_and_swift) { void *o1 = make_objc_object(); void *o2 = make_swift_object(); ASSERT_NE(o1, o2); ASSERT_NE(o1, nullptr); ASSERT_NE(o2, nullptr); DestroyedObjCCount = 0; WeakReference ref1; swift_unknownWeakInit(&ref1, o1); void *tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(tmp, o1); unknown_release(tmp); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o1, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); swift_unknownWeakAssign(&ref1, o2); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); ASSERT_EQ(0U, DestroyedObjCCount); unknown_release(o1); ASSERT_EQ(1U, DestroyedObjCCount); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(o2, tmp); unknown_release(tmp); ASSERT_EQ(1U, DestroyedObjCCount); unknown_release(o2); ASSERT_EQ(1U, DestroyedObjCCount); tmp = swift_unknownWeakLoadStrong(&ref1); ASSERT_EQ(nullptr, tmp); unknown_release(tmp); ASSERT_EQ(1U, DestroyedObjCCount); swift_unknownWeakDestroy(&ref1); } TEST(WeakTest, objc_weak_release_after_strong_release) { DestroyedObjCCount = 0; void *o = make_objc_object(); // strong 1, unowned 0 swift_unknownWeakRetain(o); // strong 1, unowned 1 swift_unknownRelease(o); // strong 0, unowned 1 -- object gets greedily deallocated by ObjC runtime ASSERT_EQ(1U, DestroyedObjCCount); swift_unknownWeakRelease(o); // strong 0, unowned 0 }