Skip to content

Revert "SR-5289: Teach Mirror how to handle unowned/unmanaged references" #28821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ using TargetRelativeIndirectablePointer

struct HeapObject;
class WeakReference;
struct UnownedReference;

template <typename Runtime> struct TargetMetadata;
using Metadata = TargetMetadata<InProcess>;
Expand Down Expand Up @@ -646,9 +645,6 @@ struct TargetMetadata {
// NOTE: This *is* a box for copy-on-write existentials.
OpaqueValue *allocateBoxForExistentialIn(ValueBuffer *Buffer) const;

// Deallocate an out-of-line buffer box if one is present.
void deallocateBoxForExistentialIn(ValueBuffer *Buffer) const;

/// Get the nominal type descriptor if this metadata describes a nominal type,
/// or return null if it does not.
ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>
Expand Down
49 changes: 49 additions & 0 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,55 @@ class TargetTupleTypeFlags {
};
using TupleTypeFlags = TargetTupleTypeFlags<size_t>;

/// Field types and flags as represented in a nominal type's field/case type
/// vector.
class FieldType {
typedef uintptr_t int_type;
// Type metadata is always at least pointer-aligned, so we get at least two
// low bits to stash flags. We could use three low bits on 64-bit, and maybe
// some high bits as well.
enum : int_type {
Indirect = 1,
Weak = 2,

TypeMask = ((uintptr_t)-1) & ~(alignof(void*) - 1),
};
int_type Data;

constexpr FieldType(int_type Data) : Data(Data) {}
public:
constexpr FieldType() : Data(0) {}
FieldType withType(const Metadata *T) const {
return FieldType((Data & ~TypeMask) | (uintptr_t)T);
}

constexpr FieldType withIndirect(bool indirect) const {
return FieldType((Data & ~Indirect)
| (indirect ? Indirect : 0));
}

constexpr FieldType withWeak(bool weak) const {
return FieldType((Data & ~Weak)
| (weak ? Weak : 0));
}

bool isIndirect() const {
return bool(Data & Indirect);
}

bool isWeak() const {
return bool(Data & Weak);
}

const Metadata *getType() const {
return (const Metadata *)(Data & TypeMask);
}

int_type getIntValue() const {
return Data;
}
};

/// Flags for exclusivity-checking operations.
enum class ExclusivityFlags : uintptr_t {
Read = 0x0,
Expand Down
2 changes: 0 additions & 2 deletions include/swift/Runtime/ExistentialContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ struct ClassExistentialContainerImpl {
using ClassExistentialContainer = ClassExistentialContainerImpl<void *>;
using WeakClassExistentialContainer =
ClassExistentialContainerImpl<WeakReference>;
using UnownedClassExistentialContainer =
ClassExistentialContainerImpl<UnownedReference>;

} // end swift namespace

Expand Down
7 changes: 0 additions & 7 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3862,13 +3862,6 @@ template <> OpaqueValue *Metadata::allocateBoxForExistentialIn(ValueBuffer *buff
return refAndValueAddr.buffer;
}

template <> void Metadata::deallocateBoxForExistentialIn(ValueBuffer *buffer) const {
auto *vwt = getValueWitnesses();
if (vwt->isValueInline())
return;
swift_deallocBox(reinterpret_cast<HeapObject *>(buffer->PrivateData[0]));
}

template <> OpaqueValue *Metadata::allocateBufferIn(ValueBuffer *buffer) const {
auto *vwt = getValueWitnesses();
if (vwt->isValueInline())
Expand Down
12 changes: 4 additions & 8 deletions stdlib/public/runtime/Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,8 @@ class TypeReferenceOwnership {

#define REF_STORAGE(Name, ...) \
void set##Name() { Data |= Name; } \
bool is##Name() const { return Data == Name; }
bool is##Name() const { return Data & Name; }
#include "swift/AST/ReferenceStorage.def"

bool isStrong() const { return Data == 0; }
};

/// Type information consists of metadata and its ownership info,
Expand All @@ -78,11 +76,9 @@ class TypeInfo {
const Metadata *getMetadata() const { return Response.Value; }
MetadataResponse getResponse() const { return Response; }

#define REF_STORAGE(Name, ...) \
bool is##Name() const { return ReferenceOwnership.is##Name(); }
#include "swift/AST/ReferenceStorage.def"

bool isStrong() const { return ReferenceOwnership.isStrong(); }
bool isWeak() const { return ReferenceOwnership.isWeak(); }
bool isUnowned() const { return ReferenceOwnership.isUnowned(); }
bool isUnmanaged() const { return ReferenceOwnership.isUnmanaged(); }

TypeReferenceOwnership getReferenceOwnership() const {
return ReferenceOwnership;
Expand Down
169 changes: 82 additions & 87 deletions stdlib/public/runtime/ReflectionMirror.mm
Original file line number Diff line number Diff line change
Expand Up @@ -89,29 +89,6 @@ - (id)debugQuickLookObject;

namespace {

class FieldType {
const Metadata *type;
bool indirect;
TypeReferenceOwnership referenceOwnership;
public:

constexpr FieldType() : type(nullptr), indirect(false), referenceOwnership() { }
constexpr FieldType(const Metadata *T) : type(T), indirect(false), referenceOwnership() { }

static constexpr FieldType untypedEnumCase(bool indirect) {
FieldType type{};
type.indirect = indirect;
return type;
}
const Metadata *getType() const { return type; }
const TypeReferenceOwnership getReferenceOwnership() const { return referenceOwnership; }
bool isIndirect() const { return indirect; }
void setIndirect(bool value) { indirect = value; }
void setReferenceOwnership(TypeReferenceOwnership newOwnership) {
referenceOwnership = newOwnership;
}
};

/// The layout of Any.
using Any = OpaqueExistentialContainer;

Expand Down Expand Up @@ -146,63 +123,58 @@ void setReferenceOwnership(TypeReferenceOwnership newOwnership) {
return std::make_tuple(T, Value);
}

static void copyWeakFieldContents(OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
assert(type->getKind() == MetadataKind::Optional);
auto *srcContainer = reinterpret_cast<WeakClassExistentialContainer*>(fieldData);
auto *destClassContainer = reinterpret_cast<ClassExistentialContainer*>(destContainer);
destClassContainer->Value = swift_unknownObjectWeakLoadStrong(&srcContainer->Value);
auto witnessTablesSize = type->vw_size() - sizeof(WeakClassExistentialContainer);
memcpy(destClassContainer->getWitnessTables(), srcContainer->getWitnessTables(), witnessTablesSize);
}

static void copyUnownedFieldContents(OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
auto *srcContainer = reinterpret_cast<UnownedClassExistentialContainer*>(fieldData);
auto *destClassContainer = reinterpret_cast<ClassExistentialContainer*>(destContainer);
destClassContainer->Value = swift_unknownObjectUnownedLoadStrong(&srcContainer->Value);
auto witnessTablesSize = type->vw_size() - sizeof(UnownedClassExistentialContainer);
memcpy(destClassContainer->getWitnessTables(), srcContainer->getWitnessTables(), witnessTablesSize);
}

static void copyUnmanagedFieldContents(OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
// Also known as "unowned(unsafe)".
// This is simpler than the unowned/weak cases because unmanaged
// references are fundamentally the same as strong ones, so we
// can use the regular strong reference support that already
// knows how to handle existentials and Obj-C references.
type->vw_initializeWithCopy(destContainer, fieldData);
}

static AnyReturn copyFieldContents(OpaqueValue *fieldData,
const FieldType fieldType) {
Any outValue;
auto *type = fieldType.getType();
outValue.Type = type;
auto ownership = fieldType.getReferenceOwnership();
auto *destContainer = type->allocateBoxForExistentialIn(&outValue.Buffer);

if (ownership.isStrong()) {
type->vw_initializeWithCopy(destContainer, fieldData);
}
static bool loadSpecialReferenceStorage(OpaqueValue *fieldData,
const FieldType fieldType,
Any *outValue) {
// isWeak() implies a reference type via Sema.
if (!fieldType.isWeak())
return false;

// Generate a conditional clause for every known ownership type.
// If this causes errors, it's because someone added a new ownership type
// to ReferenceStorage.def and missed some related updates.
#define REF_STORAGE(Name, ...) \
else if (ownership.is##Name()) { \
copy##Name##FieldContents(destContainer, type, fieldData); \
}
#include "swift/AST/ReferenceStorage.def"

else {
// The field was declared with a reference type we don't understand.
warning(0, "Value with unrecognized reference type is reflected as ()");
// Clean up the buffer allocated above
type->deallocateBoxForExistentialIn(&outValue.Buffer);
// Return an existential containing Void
outValue.Type = &METADATA_SYM(EMPTY_TUPLE_MANGLING);
}
auto type = fieldType.getType();
assert(type->getKind() == MetadataKind::Optional);

return AnyReturn(outValue);
auto *weakField = reinterpret_cast<WeakReference *>(fieldData);
auto *strongValue = swift_unknownObjectWeakLoadStrong(weakField);

// Now that we have a strong reference, we need to create a temporary buffer
// from which to copy the whole value, which might be a native class-bound
// existential, which means we also need to copy n witness tables, for
// however many protocols are in the protocol composition. For example, if we
// are copying a:
// weak var myWeakProperty : (Protocol1 & Protocol2)?
// then we need to copy three values:
// - the instance
// - the witness table for Protocol1
// - the witness table for Protocol2

auto *weakContainer =
reinterpret_cast<WeakClassExistentialContainer *>(fieldData);

// Create a temporary existential where we can put the strong reference.
// The allocateBuffer value witness requires a ValueBuffer to own the
// allocated storage.
ValueBuffer temporaryBuffer;

auto *temporaryValue = reinterpret_cast<ClassExistentialContainer *>(
type->allocateBufferIn(&temporaryBuffer));

// Now copy the entire value out of the parent, which will include the
// witness tables.
temporaryValue->Value = strongValue;
auto valueWitnessesSize = type->getValueWitnesses()->getSize() -
sizeof(WeakClassExistentialContainer);
memcpy(temporaryValue->getWitnessTables(), weakContainer->getWitnessTables(),
valueWitnessesSize);

outValue->Type = type;
auto *opaqueValueAddr = type->allocateBoxForExistentialIn(&outValue->Buffer);
type->vw_initializeWithCopy(opaqueValueAddr,
reinterpret_cast<OpaqueValue *>(temporaryValue));

type->deallocateBufferIn(&temporaryBuffer);
swift_unknownObjectRelease(strongValue);

return true;
}


Expand Down Expand Up @@ -338,7 +310,11 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
"type '%*s' that claims to be reflectable. Its fields will show up as "
"'unknown' in Mirrors\n",
(int)typeName.length, typeName.data);
return {"unknown", FieldType(&METADATA_SYM(EMPTY_TUPLE_MANGLING))};
return {"unknown",
FieldType()
.withType(&METADATA_SYM(EMPTY_TUPLE_MANGLING))
.withIndirect(false)
.withWeak(false)};
};

auto *baseDesc = base->getTypeContextDescriptor();
Expand All @@ -349,13 +325,14 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
if (!fields)
return failedToFindMetadata();

auto &field = fields->getFields()[index];
const FieldDescriptor &descriptor = *fields;
auto &field = descriptor.getFields()[index];
// Bounds are always valid as the offset is constant.
auto name = field.getFieldName();

// Enum cases don't always have types.
if (!field.hasMangledTypeName())
return {name, FieldType::untypedEnumCase(field.isIndirectCase())};
return {name, FieldType().withIndirect(field.isIndirectCase())};

auto typeName = field.getMangledTypeName();

Expand Down Expand Up @@ -383,10 +360,10 @@ static bool _shouldReportMissingReflectionMetadataWarnings() {
(int)typeName.size(), typeName.data());
}

auto fieldType = FieldType(typeInfo.getMetadata());
fieldType.setIndirect(field.isIndirectCase());
fieldType.setReferenceOwnership(typeInfo.getReferenceOwnership());
return {name, fieldType};
return {name, FieldType()
.withType(typeInfo.getMetadata())
.withIndirect(field.isIndirectCase())
.withWeak(typeInfo.isWeak())};
}

// Implementation for structs.
Expand Down Expand Up @@ -420,6 +397,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
// Load the offset from its respective vector.
auto fieldOffset = Struct->getFieldOffsets()[i];

Any result;
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
Expand All @@ -431,7 +409,15 @@ AnyReturn subscript(intptr_t i, const char **outName,
auto *bytes = reinterpret_cast<char*>(value);
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);

return copyFieldContents(fieldData, fieldInfo);
bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
if (!didLoad) {
result.Type = fieldInfo.getType();
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
result.Type->vw_initializeWithCopy(opaqueValueAddr,
const_cast<OpaqueValue *>(fieldData));
}

return AnyReturn(result);
}
};

Expand Down Expand Up @@ -573,6 +559,7 @@ AnyReturn subscript(intptr_t i, const char **outName,
#endif
}

Any result;
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
Expand All @@ -584,7 +571,15 @@ AnyReturn subscript(intptr_t i, const char **outName,
*outName = name.data();
*outFreeFunc = nullptr;

return copyFieldContents(fieldData, fieldInfo);
bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
if (!didLoad) {
result.Type = fieldInfo.getType();
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
result.Type->vw_initializeWithCopy(opaqueValueAddr,
const_cast<OpaqueValue *>(fieldData));
}

return AnyReturn(result);
}

#if SWIFT_OBJC_INTEROP
Expand Down
Loading