Skip to content

IRGen: Make resilient enum's tag indices resilient #15208

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
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
1 change: 1 addition & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Globals
global ::= type protocol-conformance 'Wl' // lazy protocol witness table accessor
global ::= type 'WV' // value witness table
global ::= entity 'Wv' DIRECTNESS // field offset
global ::= entity 'WC' // resilient enum tag index

global ::= type 'Wy' // Outlined Copy Function Type
global ::= type 'We' // Outlined Consume Function Type
Expand Down
16 changes: 8 additions & 8 deletions include/swift/ABI/ValueWitness.def
Original file line number Diff line number Diff line change
Expand Up @@ -180,23 +180,23 @@ FUNCTION_VALUE_WITNESS(initializeBufferWithTakeOfBuffer,
MUTABLE_VALUE_TYPE,
(MUTABLE_BUFFER_TYPE, MUTABLE_BUFFER_TYPE, TYPE_TYPE))

/// int (*getEnumTagSinglePayload)(const T* enum, UINT_TYPE emptyCases)
/// unsigned (*getEnumTagSinglePayload)(const T* enum, UINT_TYPE emptyCases)
/// Given an instance of valid single payload enum with a payload of this
/// witness table's type (e.g Optional<ThisType>) , get the tag of the enum.
FUNCTION_VALUE_WITNESS(getEnumTagSinglePayload,
GetEnumTagSinglePayload,
INT_TYPE,
UINT_TYPE,
(IMMUTABLE_VALUE_TYPE, UINT_TYPE, TYPE_TYPE))

/// void (*storeEnumTagSinglePayload)(T* enum, INT_TYPE whichCase,
/// void (*storeEnumTagSinglePayload)(T* enum, UINT_TYPE whichCase,
/// UINT_TYPE emptyCases)
/// Given uninitialized memory for an instance of a single payload enum with a
/// payload of this witness table's type (e.g Optional<ThisType>), store the
/// tag.
FUNCTION_VALUE_WITNESS(storeEnumTagSinglePayload,
StoreEnumTagSinglePayload,
VOID_TYPE,
(MUTABLE_VALUE_TYPE, INT_TYPE, UINT_TYPE, TYPE_TYPE))
(MUTABLE_VALUE_TYPE, UINT_TYPE, UINT_TYPE, TYPE_TYPE))

END_VALUE_WITNESS_RANGE(RequiredValueWitnessFunction,
StoreEnumTagSinglePayload)
Expand Down Expand Up @@ -327,11 +327,11 @@ END_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitness,
// The following value witnesses are conditionally present if the witnessed
// type is an enum.

/// int (*getEnumTag)(T *obj, M *self);
/// unsigned (*getEnumTag)(T *obj, M *self);
///
/// Given a valid object of this enum type, extracts the tag value indicating
/// which case of the enum is inhabited. Returned values are in the range
/// [-ElementsWithPayload..ElementsWithNoPayload-1].
/// [0..NumElements-1].
FUNCTION_VALUE_WITNESS(getEnumTag,
GetEnumTag,
INT_TYPE,
Expand All @@ -348,14 +348,14 @@ FUNCTION_VALUE_WITNESS(destructiveProjectEnumData,
VOID_TYPE,
(MUTABLE_VALUE_TYPE, TYPE_TYPE))

/// void (*destructiveInjectEnumTag)(T *obj, int tag, M *self);
/// void (*destructiveInjectEnumTag)(T *obj, unsigned tag, M *self);
/// Given an enum case tag and a valid object of case's payload type,
/// destructively inserts the tag into the payload. The given tag value
/// must be in the range [-ElementsWithPayload..ElementsWithNoPayload-1].
FUNCTION_VALUE_WITNESS(destructiveInjectEnumTag,
DestructiveInjectEnumTag,
VOID_TYPE,
(MUTABLE_VALUE_TYPE, INT_TYPE, TYPE_TYPE))
(MUTABLE_VALUE_TYPE, UINT_TYPE, TYPE_TYPE))

END_VALUE_WITNESS_RANGE(EnumValueWitness,
DestructiveInjectEnumTag)
Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ NODE(DynamicAttribute)
NODE(DirectMethodReferenceAttribute)
NODE(DynamicSelf)
CONTEXT_NODE(Enum)
NODE(EnumCase)
NODE(ErrorType)
NODE(EscapingAutoClosureType)
NODE(NoEscapeFunctionType)
Expand Down
9 changes: 9 additions & 0 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ class LinkEntity {
/// ConstructorDecl* inside a protocol or a class.
DispatchThunkAllocator,

/// A resilient enum tag index. The pointer is a EnumElementDecl*.
EnumCase,

/// A field offset. The pointer is a VarDecl*.
FieldOffset,

Expand Down Expand Up @@ -434,6 +437,12 @@ class LinkEntity {
return entity;
}

static LinkEntity forEnumCase(EnumElementDecl *decl) {
LinkEntity entity;
entity.setForDecl(Kind::EnumCase, decl);
return entity;
}

static LinkEntity forObjCClassRef(ClassDecl *decl) {
LinkEntity entity;
entity.setForDecl(Kind::ObjCClassRef, decl);
Expand Down
21 changes: 10 additions & 11 deletions include/swift/Runtime/Enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,30 +64,29 @@ void swift_initEnumMetadataSinglePayload(EnumMetadata *enumType,
/// \param payload - type metadata for the payload case of the enum.
/// \param emptyCases - the number of empty cases in the enum.
///
/// \returns -1 if the payload case is inhabited. If an empty case is inhabited,
/// returns a value greater than or equal to zero and less than
/// \returns 0 if the payload case is inhabited. If an empty case is inhabited,
/// returns a value greater than or equal to one and less than or equal
/// emptyCases.
SWIFT_RUNTIME_EXPORT
int swift_getEnumCaseSinglePayload(const OpaqueValue *value,
const Metadata *payload,
unsigned emptyCases);

unsigned swift_getEnumCaseSinglePayload(const OpaqueValue *value,
const Metadata *payload,
unsigned emptyCases);

/// \brief Store the tag value for the given case into a single-payload enum,
/// whose associated payload (if any) has already been initialized.
///
/// \param value - pointer to the enum value. If the case being initialized is
/// the payload case (-1), then the payload should be
/// the payload case (0), then the payload should be
/// initialized.
/// \param payload - type metadata for the payload case of the enum.
/// \param whichCase - unique value identifying the case. -1 for the payload
/// case, or a value greater than or equal to zero and less
/// than emptyCases for an empty case.
/// \param whichCase - unique value identifying the case. 0 for the payload
/// case, or a value greater than or equal to one and less
/// than or equal emptyCases for an empty case.
/// \param emptyCases - the number of empty cases in the enum.
SWIFT_RUNTIME_EXPORT
void swift_storeEnumTagSinglePayload(OpaqueValue *value,
const Metadata *payload,
int whichCase,
unsigned whichCase,
unsigned emptyCases);

/// \brief Initialize the type metadata for a generic, multi-payload
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ struct TargetMetadata {
getValueWitnesses()->_asXIVWT()->storeExtraInhabitant(value, index, this);
}

int vw_getEnumTag(const OpaqueValue *value) const {
unsigned vw_getEnumTag(const OpaqueValue *value) const {
return getValueWitnesses()->_asEVWT()->getEnumTag(const_cast<OpaqueValue*>(value), this);
}
void vw_destructiveProjectEnumData(OpaqueValue *value) const {
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -987,7 +987,7 @@ FUNCTION(GetEnumCaseMultiPayload,
ATTRS(NoUnwind, ReadOnly))

// void swift_storeEnumTagSinglePayload(opaque_t *obj, Metadata *payload,
// int case_index,
// unsigned case_index,
// unsigned num_empty_cases);
FUNCTION(StoreEnumTagSinglePayload,
swift_storeEnumTagSinglePayload,
Expand Down
3 changes: 3 additions & 0 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2049,6 +2049,9 @@ NodePointer Demangler::demangleSpecAttributes(Node::Kind SpecKind,

NodePointer Demangler::demangleWitness() {
switch (nextChar()) {
case 'C':
return createWithChild(Node::Kind::EnumCase,
popNode(isEntity));
case 'V':
return createWithChild(Node::Kind::ValueWitnessTable,
popNode(Node::Kind::Type));
Expand Down
7 changes: 7 additions & 0 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ class NodePrinter {
case Node::Kind::NoEscapeFunctionType:
case Node::Kind::ExplicitClosure:
case Node::Kind::Extension:
case Node::Kind::EnumCase:
case Node::Kind::FieldOffset:
case Node::Kind::FullTypeMetadata:
case Node::Kind::Function:
Expand Down Expand Up @@ -1397,6 +1398,12 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
print(entity, /*asContext*/ false);
return nullptr;
}
case Node::Kind::EnumCase: {
Printer << "enum case for ";
auto entity = Node->getChild(0);
print(entity, /*asContext*/ false);
return nullptr;
}
case Node::Kind::ReabstractionThunk:
case Node::Kind::ReabstractionThunkHelper: {
if (Options.ShortenThunk) {
Expand Down
5 changes: 5 additions & 0 deletions lib/Demangling/OldRemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,11 @@ void Remangler::mangleFieldOffset(Node *node) {
mangleChildNodes(node); // directness, entity
}

void Remangler::mangleEnumCase(Node *node) {
Out << "WC";
mangleSingleChildNode(node); // enum case
}

void Remangler::mangleProtocolWitnessTable(Node *node) {
Out << "WP";
mangleSingleChildNode(node); // protocol conformance
Expand Down
5 changes: 5 additions & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,11 @@ void Remangler::mangleFieldOffset(Node *node) {
mangleChildNode(node, 0); // directness
}

void Remangler::mangleEnumCase(Node *node) {
mangleSingleChildNode(node); // enum case
Buffer << "WC";
}

void Remangler::mangleFullTypeMetadata(Node *node) {
mangleSingleChildNode(node);
Buffer << "Mf";
Expand Down
16 changes: 16 additions & 0 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1521,6 +1521,12 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
case Kind::CoroutineContinuationPrototype:
return SILLinkage::PublicExternal;


case Kind::EnumCase: {
auto *elementDecl = cast<EnumElementDecl>(getDecl());
return getSILLinkage(getDeclLinkage(elementDecl), forDefinition);
}

case Kind::FieldOffset: {
auto *varDecl = cast<VarDecl>(getDecl());

Expand Down Expand Up @@ -1644,6 +1650,9 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
case Kind::ProtocolDescriptor:
return ::isAvailableExternally(IGM, getDecl());

case Kind::EnumCase:
return ::isAvailableExternally(IGM, getDecl());

case Kind::DirectProtocolWitnessTable:
case Kind::ProtocolConformanceDescriptor:
return ::isAvailableExternally(IGM, getProtocolConformance()->getDeclContext());
Expand Down Expand Up @@ -3571,6 +3580,13 @@ Address IRGenModule::getAddrOfFieldOffset(VarDecl *var,
forDefinition);
}

Address IRGenModule::getAddrOfEnumCase(EnumElementDecl *Case,
ForDefinition_t forDefinition) {
LinkEntity entity = LinkEntity::forEnumCase(Case);
return getAddrOfSimpleVariable(*this, GlobalVars, entity, Int32Ty,
getPointerAlignment(), forDefinition);
}

void IRGenModule::emitNestedTypeDecls(DeclRange members) {
for (Decl *member : members) {
switch (member->getKind()) {
Expand Down
Loading