mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
We can't do this because the object was deallocated. However, ASan should flag us if we regress on touching deallocated unowned-referenced objects though, so we don't need this. rdar://problem/19677703 Swift SVN r24894
304 lines
7.1 KiB
Plaintext
304 lines
7.1 KiB
Plaintext
//===- 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 <Foundation/NSObject.h>
|
|
#include <objc/runtime.h>
|
|
#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
|
|
}
|