Skip to content

Preserve 'let'-ness of stored properties in key paths. #18768

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 3 commits into from
Aug 17, 2018
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
55 changes: 34 additions & 21 deletions include/swift/ABI/KeyPath.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,65 +82,78 @@ class KeyPathComponentHeader {
offset;
}

static constexpr uint32_t isLetBit(bool isLet) {
return isLet ? 0 : _SwiftKeyPathComponentHeader_StoredMutableFlag;
}

public:
static constexpr bool offsetCanBeInline(unsigned offset) {
return offset <= _SwiftKeyPathComponentHeader_MaximumOffsetPayload;
}

constexpr static KeyPathComponentHeader
forStructComponentWithInlineOffset(unsigned offset) {
forStructComponentWithInlineOffset(bool isLet,
unsigned offset) {
return KeyPathComponentHeader(
(_SwiftKeyPathComponentHeader_StructTag
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| validateInlineOffset(offset));
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| validateInlineOffset(offset)
| isLetBit(isLet));
}

constexpr static KeyPathComponentHeader
forStructComponentWithOutOfLineOffset() {
forStructComponentWithOutOfLineOffset(bool isLet) {
return KeyPathComponentHeader(
(_SwiftKeyPathComponentHeader_StructTag
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_OutOfLineOffsetPayload);
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_OutOfLineOffsetPayload
| isLetBit(isLet));
}

constexpr static KeyPathComponentHeader
forStructComponentWithUnresolvedFieldOffset() {
forStructComponentWithUnresolvedFieldOffset(bool isLet) {
return KeyPathComponentHeader(
(_SwiftKeyPathComponentHeader_StructTag
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_UnresolvedFieldOffsetPayload);
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_UnresolvedFieldOffsetPayload
| isLetBit(isLet));
}

constexpr static KeyPathComponentHeader
forClassComponentWithInlineOffset(unsigned offset) {
forClassComponentWithInlineOffset(bool isLet,
unsigned offset) {
return KeyPathComponentHeader(
(_SwiftKeyPathComponentHeader_ClassTag
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| validateInlineOffset(offset));
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| validateInlineOffset(offset)
| isLetBit(isLet));
}

constexpr static KeyPathComponentHeader
forClassComponentWithOutOfLineOffset() {
forClassComponentWithOutOfLineOffset(bool isLet) {
return KeyPathComponentHeader(
(_SwiftKeyPathComponentHeader_ClassTag
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_OutOfLineOffsetPayload);
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_OutOfLineOffsetPayload
| isLetBit(isLet));
}

constexpr static KeyPathComponentHeader
forClassComponentWithUnresolvedFieldOffset() {
forClassComponentWithUnresolvedFieldOffset(bool isLet) {
return KeyPathComponentHeader(
(_SwiftKeyPathComponentHeader_ClassTag
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_UnresolvedFieldOffsetPayload);
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_UnresolvedFieldOffsetPayload
| isLetBit(isLet));
}

constexpr static KeyPathComponentHeader
forClassComponentWithUnresolvedIndirectOffset() {
forClassComponentWithUnresolvedIndirectOffset(bool isLet) {
return KeyPathComponentHeader(
(_SwiftKeyPathComponentHeader_ClassTag
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_UnresolvedIndirectOffsetPayload);
<< _SwiftKeyPathComponentHeader_DiscriminatorShift)
| _SwiftKeyPathComponentHeader_UnresolvedIndirectOffsetPayload
| isLetBit(isLet));
}

constexpr static KeyPathComponentHeader
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,10 @@ void verifyMangledNameRoundtrip(const Metadata *metadata);
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const TypeContextDescriptor *swift_getTypeContextDescriptor(const Metadata *type);

// Defined in KeyPath.swift in the standard library.
SWIFT_RUNTIME_EXPORT
const HeapObject *swift_getKeyPath(const void *pattern, const void *arguments);

} // end namespace swift

#endif // SWIFT_RUNTIME_METADATA_H
23 changes: 12 additions & 11 deletions lib/IRGen/GenKeyPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -773,22 +773,23 @@ emitKeyPathComponent(IRGenModule &IGM,
case KeyPathPatternComponent::Kind::StoredProperty: {
auto property = cast<VarDecl>(component.getStoredPropertyDecl());

auto addFixedOffset = [&](bool isStruct, llvm::Constant *offset) {
auto addFixedOffset = [&](bool isStruct, bool isLet,
llvm::Constant *offset) {
if (auto offsetInt = dyn_cast_or_null<llvm::ConstantInt>(offset)) {
auto offsetValue = offsetInt->getValue().getZExtValue();
if (KeyPathComponentHeader::offsetCanBeInline(offsetValue)) {
auto header = isStruct
? KeyPathComponentHeader
::forStructComponentWithInlineOffset(offsetValue)
::forStructComponentWithInlineOffset(isLet, offsetValue)
: KeyPathComponentHeader
::forClassComponentWithInlineOffset(offsetValue);
::forClassComponentWithInlineOffset(isLet, offsetValue);
fields.addInt32(header.getData());
return;
}
}
auto header = isStruct
? KeyPathComponentHeader::forStructComponentWithOutOfLineOffset()
: KeyPathComponentHeader::forClassComponentWithOutOfLineOffset();
? KeyPathComponentHeader::forStructComponentWithOutOfLineOffset(isLet)
: KeyPathComponentHeader::forClassComponentWithOutOfLineOffset(isLet);
fields.addInt32(header.getData());
fields.add(llvm::ConstantExpr::getTruncOrBitCast(offset, IGM.Int32Ty));
};
Expand All @@ -801,7 +802,7 @@ emitKeyPathComponent(IRGenModule &IGM,
loweredBaseTy,
property)) {
// We have a known constant fixed offset.
addFixedOffset(/*struct*/ true, offset);
addFixedOffset(/*struct*/ true, property->isLet(), offset);
break;
}

Expand All @@ -811,7 +812,7 @@ emitKeyPathComponent(IRGenModule &IGM,
auto fieldOffset = metadataLayout.getStaticFieldOffset(property);

auto header = KeyPathComponentHeader
::forStructComponentWithUnresolvedFieldOffset();
::forStructComponentWithUnresolvedFieldOffset(property->isLet());
fields.addInt32(header.getData());
fields.addInt32(fieldOffset.getValue());
break;
Expand All @@ -829,14 +830,14 @@ emitKeyPathComponent(IRGenModule &IGM,
loweredBaseTy,
property);
assert(offset && "no constant offset for ConstantDirect field?!");
addFixedOffset(/*struct*/ false, offset);
addFixedOffset(/*struct*/ false, property->isLet(), offset);
break;
}
case FieldAccess::NonConstantDirect: {
// A constant offset that's determined at class realization time.
// We have to load the offset from a global ivar.
auto header = KeyPathComponentHeader
::forClassComponentWithUnresolvedIndirectOffset();
::forClassComponentWithUnresolvedIndirectOffset(property->isLet());
fields.addInt32(header.getData());
fields.addAlignmentPadding(IGM.getPointerAlignment());
auto offsetVar = IGM.getAddrOfFieldOffset(property, NotForDefinition);
Expand All @@ -846,8 +847,8 @@ emitKeyPathComponent(IRGenModule &IGM,
case FieldAccess::ConstantIndirect: {
// An offset that depends on the instance's generic parameterization,
// but whose field offset is at a known vtable offset.
auto header =
KeyPathComponentHeader::forClassComponentWithUnresolvedFieldOffset();
auto header = KeyPathComponentHeader
::forClassComponentWithUnresolvedFieldOffset(property->isLet());
fields.addInt32(header.getData());
auto fieldOffset =
getClassFieldOffsetOffset(IGM,
Expand Down
14 changes: 10 additions & 4 deletions stdlib/public/SwiftShims/KeyPath.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,23 @@ static const __swift_uint32_t _SwiftKeyPathComponentHeader_ExternalTag
static const __swift_uint32_t
_SwiftKeyPathComponentHeader_TrivialPropertyDescriptorMarker = 0U;

static const __swift_uint32_t _SwiftKeyPathComponentHeader_StoredOffsetPayloadMask
= 0x007FFFFFU;

static const __swift_uint32_t _SwiftKeyPathComponentHeader_MaximumOffsetPayload
= 0x00FFFFFCU;
= 0x007FFFFCU;

static const __swift_uint32_t _SwiftKeyPathComponentHeader_UnresolvedIndirectOffsetPayload
= 0x00FFFFFDU;
= 0x007FFFFDU;

static const __swift_uint32_t _SwiftKeyPathComponentHeader_UnresolvedFieldOffsetPayload
= 0x00FFFFFEU;
= 0x007FFFFEU;

static const __swift_uint32_t _SwiftKeyPathComponentHeader_OutOfLineOffsetPayload
= 0x00FFFFFFU;
= 0x007FFFFFU;

static const __swift_uint32_t _SwiftKeyPathComponentHeader_StoredMutableFlag
= 0x00800000U;

static const __swift_uint32_t _SwiftKeyPathComponentHeader_OptionalChainPayload
= 0;
Expand Down
Loading