mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This is a bit of a hodge-podge of related changes that I decided
weren't quite worth teasing apart:
First, rename the weak{Retain,Release} entrypoints to
unowned{Retain,Release} to better reflect their actual use
from generated code.
Second, standardize the names of the rest of the entrypoints around
unowned{operation}.
Third, standardize IRGen's internal naming scheme and API for
reference-counting so that (1) there are generic functions for
emitting operations using a given reference-counting style and
(2) all operations explicitly call out the kind and style of
reference counting.
Finally, implement a number of new entrypoints for unknown unowned
reference-counting. These entrypoints use a completely different
and incompatible scheme for working with ObjC references. The
primary difference is that the new scheme abandons the flawed idea
(which I take responsibility for) that we can simulate an unowned
reference count for ObjC references, and instead moves towards an
address-only scheme when the reference might store an ObjC reference.
(The current implementation is still trivially takable, but that is
not something we should be relying on.) These will be tested in a
follow-up commit. For now, we still rely on the bad assumption of
reference-countability.
159 lines
4.7 KiB
C++
159 lines
4.7 KiB
C++
//===swift/unittests/runtime/Refcounting.cpp - Reference-counting for swift===//
|
|
//
|
|
// 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 "swift/Runtime/HeapObject.h"
|
|
#include "swift/Runtime/Metadata.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace swift;
|
|
|
|
struct TestObject : HeapObject {
|
|
size_t *Addr;
|
|
size_t Value;
|
|
};
|
|
|
|
static void destroyTestObject(HeapObject *_object) {
|
|
auto object = static_cast<TestObject*>(_object);
|
|
assert(object->Addr && "object already deallocated");
|
|
*object->Addr = object->Value;
|
|
object->Addr = nullptr;
|
|
swift_deallocObject(object, sizeof(TestObject), alignof(TestObject) - 1);
|
|
}
|
|
|
|
static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
|
|
{ { &destroyTestObject }, { &_TWVBo } },
|
|
{ { { MetadataKind::Class } }, 0, /*rodata*/ 1,
|
|
ClassFlags::UsesSwift1Refcounting, nullptr, nullptr, 0, 0, 0, 0, 0 }
|
|
};
|
|
|
|
/// Create an object that, when deallocated, stores the given value to
|
|
/// the given pointer.
|
|
static TestObject *allocTestObject(size_t *addr, size_t value) {
|
|
auto result =
|
|
static_cast<TestObject *>(swift_allocObject(&TestClassObjectMetadata,
|
|
sizeof(TestObject),
|
|
alignof(TestObject) - 1));
|
|
result->Addr = addr;
|
|
result->Value = value;
|
|
return result;
|
|
}
|
|
|
|
TEST(RefcountingTest, release) {
|
|
size_t value = 0;
|
|
auto object = allocTestObject(&value, 1);
|
|
EXPECT_EQ(0u, value);
|
|
swift_release(object);
|
|
EXPECT_EQ(1u, value);
|
|
}
|
|
|
|
TEST(RefcountingTest, retain_release) {
|
|
size_t value = 0;
|
|
auto object = allocTestObject(&value, 1);
|
|
EXPECT_EQ(0u, value);
|
|
swift_retain(object);
|
|
EXPECT_EQ(0u, value);
|
|
swift_release(object);
|
|
EXPECT_EQ(0u, value);
|
|
swift_release(object);
|
|
EXPECT_EQ(1u, value);
|
|
}
|
|
|
|
TEST(RefcountingTest, pin_unpin) {
|
|
size_t value = 0;
|
|
auto object = allocTestObject(&value, 1);
|
|
EXPECT_EQ(0u, value);
|
|
auto pinResult = swift_tryPin(object);
|
|
EXPECT_EQ(object, pinResult);
|
|
EXPECT_EQ(0u, value);
|
|
swift_release(object);
|
|
EXPECT_EQ(0u, value);
|
|
swift_unpin(object);
|
|
EXPECT_EQ(1u, value);
|
|
}
|
|
|
|
TEST(RefcountingTest, pin_pin_unpin_unpin) {
|
|
size_t value = 0;
|
|
auto object = allocTestObject(&value, 1);
|
|
EXPECT_EQ(0u, value);
|
|
auto pinResult = swift_tryPin(object);
|
|
EXPECT_EQ(object, pinResult);
|
|
EXPECT_EQ(0u, value);
|
|
auto pinResult2 = swift_tryPin(object);
|
|
EXPECT_EQ(nullptr, pinResult2);
|
|
EXPECT_EQ(0u, value);
|
|
swift_unpin(pinResult2);
|
|
EXPECT_EQ(0u, value);
|
|
swift_release(object);
|
|
EXPECT_EQ(0u, value);
|
|
swift_unpin(object);
|
|
EXPECT_EQ(1u, value);
|
|
}
|
|
|
|
TEST(RefcountingTest, retain_release_n) {
|
|
size_t value = 0;
|
|
auto object = allocTestObject(&value, 1);
|
|
EXPECT_EQ(0u, value);
|
|
swift_retain_n(object, 32);
|
|
swift_retain(object);
|
|
EXPECT_EQ(0u, value);
|
|
EXPECT_EQ(34u, swift_retainCount(object));
|
|
swift_release_n(object, 31);
|
|
EXPECT_EQ(0u, value);
|
|
EXPECT_EQ(3u, swift_retainCount(object));
|
|
swift_release(object);
|
|
EXPECT_EQ(0u, value);
|
|
EXPECT_EQ(2u, swift_retainCount(object));
|
|
swift_release_n(object, 1);
|
|
EXPECT_EQ(0u, value);
|
|
EXPECT_EQ(1u, swift_retainCount(object));
|
|
swift_release(object);
|
|
EXPECT_EQ(1u, value);
|
|
}
|
|
|
|
TEST(RefcountingTest, unknown_retain_release_n) {
|
|
size_t value = 0;
|
|
auto object = allocTestObject(&value, 1);
|
|
EXPECT_EQ(0u, value);
|
|
swift_unknownRetain_n(object, 32);
|
|
swift_unknownRetain(object);
|
|
EXPECT_EQ(0u, value);
|
|
EXPECT_EQ(34u, swift_retainCount(object));
|
|
swift_unknownRelease_n(object, 31);
|
|
EXPECT_EQ(0u, value);
|
|
EXPECT_EQ(3u, swift_retainCount(object));
|
|
swift_unknownRelease(object);
|
|
EXPECT_EQ(0u, value);
|
|
EXPECT_EQ(2u, swift_retainCount(object));
|
|
swift_unknownRelease_n(object, 1);
|
|
EXPECT_EQ(0u, value);
|
|
EXPECT_EQ(1u, swift_retainCount(object));
|
|
swift_unknownRelease(object);
|
|
EXPECT_EQ(1u, value);
|
|
}
|
|
|
|
TEST(RefcountingTest, unowned_retain_release_n) {
|
|
size_t value = 0;
|
|
auto object = allocTestObject(&value, 1);
|
|
EXPECT_EQ(0u, value);
|
|
swift_unownedRetain_n(object, 32);
|
|
swift_unownedRetain(object);
|
|
EXPECT_EQ(34u, swift_unownedRetainCount(object));
|
|
swift_unownedRelease_n(object, 31);
|
|
EXPECT_EQ(3u, swift_unownedRetainCount(object));
|
|
swift_unownedRelease(object);
|
|
EXPECT_EQ(2u, swift_unownedRetainCount(object));
|
|
swift_unownedRelease_n(object, 1);
|
|
EXPECT_EQ(1u, swift_unownedRetainCount(object));
|
|
swift_release(object);
|
|
EXPECT_EQ(1u, value);
|
|
}
|