Skip to content

Debugger support for opaque types. #24445

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 8 commits into from
May 3, 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
20 changes: 13 additions & 7 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ template <typename Runtime> struct TargetStructMetadata;
template <typename Runtime> struct TargetOpaqueMetadata;
template <typename Runtime> struct TargetValueMetadata;
template <typename Runtime> struct TargetForeignClassMetadata;
template <typename Runtime> struct TargetContextDescriptor;
template <typename Runtime> class TargetTypeContextDescriptor;
template <typename Runtime> class TargetClassDescriptor;
template <typename Runtime> class TargetValueTypeDescriptor;
Expand Down Expand Up @@ -2085,12 +2086,12 @@ struct TargetTypeMetadataRecord {
private:
union {
/// A direct reference to a nominal type descriptor.
RelativeDirectPointerIntPair<TargetTypeContextDescriptor<Runtime>,
RelativeDirectPointerIntPair<TargetContextDescriptor<Runtime>,
TypeReferenceKind>
DirectNominalTypeDescriptor;

/// An indirect reference to a nominal type descriptor.
RelativeDirectPointerIntPair<TargetTypeContextDescriptor<Runtime> * const,
RelativeDirectPointerIntPair<TargetContextDescriptor<Runtime> * const,
TypeReferenceKind>
IndirectNominalTypeDescriptor;

Expand All @@ -2103,8 +2104,8 @@ struct TargetTypeMetadataRecord {
return DirectNominalTypeDescriptor.getInt();
}

const TargetTypeContextDescriptor<Runtime> *
getTypeContextDescriptor() const {
const TargetContextDescriptor<Runtime> *
getContextDescriptor() const {
switch (getTypeKind()) {
case TypeReferenceKind::DirectTypeDescriptor:
return DirectNominalTypeDescriptor.getPointer();
Expand Down Expand Up @@ -3043,11 +3044,16 @@ struct TargetOpaqueTypeDescriptor final
return getNumUnderlyingTypeArguments();
}

const RelativeDirectPointer<const char> &
getUnderlyingTypeArgumentMangledName(unsigned i) const {
assert(i < getNumUnderlyingTypeArguments());
return (this
->template getTrailingObjects<RelativeDirectPointer<const char>>())[i];
}

StringRef getUnderlyingTypeArgument(unsigned i) const {
assert(i < getNumUnderlyingTypeArguments());
const char *ptr =
(this->template getTrailingObjects<RelativeDirectPointer<const char>>())[i];

const char *ptr = getUnderlyingTypeArgumentMangledName(i);
return Demangle::makeSymbolicMangledNameStringRef(ptr);
}

Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ class ASTMangler : public Mangler {

std::string mangleTypeForDebugger(Type decl, const DeclContext *DC);

std::string mangleOpaqueTypeDescriptor(const OpaqueTypeDecl *decl);

std::string mangleDeclType(const ValueDecl *decl);

std::string mangleObjCRuntimeName(const NominalTypeDecl *Nominal);
Expand Down
12 changes: 12 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -4802,6 +4802,18 @@ class OpaqueTypeArchetypeType final : public ArchetypeType,
return T->getKind() == TypeKind::OpaqueTypeArchetype;
}

/// Get the ordinal of the type within the declaration's opaque signature.
///
/// If a method declared its return type as:
///
/// func foo() -> (some P, some Q)
///
/// then the underlying type of `some P` would be ordinal 0, and `some Q` would be ordinal 1.
unsigned getOrdinal() const {
// TODO: multiple opaque types
return 0;
}

static void Profile(llvm::FoldingSetNodeID &ID,
OpaqueTypeDecl *OpaqueDecl,
SubstitutionMap Substitutions);
Expand Down
10 changes: 6 additions & 4 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -770,9 +770,10 @@ class LinkEntity {
return entity;
}

static LinkEntity forAnonymousDescriptor(DeclContext *dc) {
static LinkEntity forAnonymousDescriptor(
PointerUnion<DeclContext *, VarDecl *> dc) {
LinkEntity entity;
entity.Pointer = const_cast<void*>(static_cast<const void*>(dc));
entity.Pointer = dc.getOpaqueValue();
entity.SecondaryPointer = nullptr;
entity.Data =
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::AnonymousDescriptor));
Expand Down Expand Up @@ -1015,9 +1016,10 @@ class LinkEntity {
return reinterpret_cast<ExtensionDecl*>(Pointer);
}

const DeclContext *getDeclContext() const {
const PointerUnion<DeclContext *, VarDecl *> getAnonymousDeclContext() const {
assert(getKind() == Kind::AnonymousDescriptor);
return reinterpret_cast<DeclContext*>(Pointer);
return PointerUnion<DeclContext *, VarDecl *>
::getFromOpaqueValue(reinterpret_cast<void*>(Pointer));
}

SILFunction *getSILFunction() const {
Expand Down
58 changes: 58 additions & 0 deletions include/swift/Remote/MetadataReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,35 @@ class MetadataReader {
return nullptr;
return buildContextMangling(context, Dem);
}

/// Read the mangled underlying type from an opaque type descriptor.
BuiltType
readUnderlyingTypeForOpaqueTypeDescriptor(StoredPointer contextAddr,
unsigned ordinal) {
auto context = readContextDescriptor(contextAddr);
if (!context)
return BuiltType();
if (context->getKind() != ContextDescriptorKind::OpaqueType)
return BuiltType();

auto opaqueType =
reinterpret_cast<const TargetOpaqueTypeDescriptor<Runtime> *>(
context.getLocalBuffer());

if (ordinal >= opaqueType->getNumUnderlyingTypeArguments())
return BuiltType();

auto nameAddr = resolveRelativeField(context,
opaqueType->getUnderlyingTypeArgumentMangledName(ordinal));

Demangle::Demangler Dem;
auto node = readMangledName(RemoteAddress(nameAddr),
MangledNameKind::Type, Dem);
if (!node)
return BuiltType();

return decodeMangledType(node);
}

bool isTaggedPointer(StoredPointer objectAddress) {
if (getTaggedPointerEncoding() != TaggedPointerEncodingKind::Extended)
Expand Down Expand Up @@ -1396,6 +1425,12 @@ class MetadataReader {
case ContextDescriptorKind::Protocol:
baseSize = sizeof(TargetProtocolDescriptor<Runtime>);
break;
case ContextDescriptorKind::OpaqueType:
baseSize = sizeof(TargetOpaqueTypeDescriptor<Runtime>);
metadataInitSize =
sizeof(typename Runtime::template RelativeDirectPointer<const char>)
* flags.getKindSpecificFlags();
break;
default:
// We don't know about this kind of context.
return nullptr;
Expand Down Expand Up @@ -2076,6 +2111,29 @@ class MetadataReader {
// contexts; just create the node directly here and return.
return dem.createNode(nodeKind, std::move(moduleName));
}

case ContextDescriptorKind::OpaqueType: {
// The opaque type may have a named anonymous context for us to map
// back to its defining decl.
if (!parentDescriptorResult)
return nullptr;
auto anonymous =
dyn_cast_or_null<TargetAnonymousContextDescriptor<Runtime>>(
parentDescriptorResult->getLocalBuffer());
if (!anonymous)
return nullptr;

auto mangledNode =
demangleAnonymousContextName(*parentDescriptorResult, dem);
if (!mangledNode)
return nullptr;
if (mangledNode->getKind() == Node::Kind::Global)
mangledNode = mangledNode->getChild(0);

auto opaqueNode = dem.createNode(Node::Kind::OpaqueReturnTypeOf);
opaqueNode->addChild(mangledNode, dem);
return opaqueNode;
}

default:
// Not a kind of context we know about.
Expand Down
11 changes: 11 additions & 0 deletions include/swift/RemoteAST/RemoteAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,17 @@ class RemoteASTContext {
Result<OpenedExistential>
getDynamicTypeAndAddressForExistential(remote::RemoteAddress address,
Type staticType);

/// Given a reference to an opaque type descriptor, an ordinal, and a set
/// of substitutions, get the underlying type for the opaque type.
///
/// This does not recursively apply the transformation if the underlying
/// type in turn refers to another opaque type.
Result<Type>
getUnderlyingTypeForOpaqueType(remote::RemoteAddress opaqueDescriptor,
SubstitutionMap substitutions,
unsigned ordinal);

};

} // end namespace remoteAST
Expand Down
7 changes: 5 additions & 2 deletions lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,14 @@ Type ASTBuilder::resolveOpaqueType(NodePointer opaqueDescriptor,
unsigned ordinal) {
if (opaqueDescriptor->getKind() == Node::Kind::OpaqueReturnTypeOf) {
auto definingDecl = opaqueDescriptor->getChild(0);
auto mangledName = mangleNode(definingDecl);
auto definingGlobal = Factory.createNode(Node::Kind::Global);
definingGlobal->addChild(definingDecl, Factory);
auto mangledName = mangleNode(definingGlobal);

auto moduleNode = findModuleNode(definingDecl);
if (!moduleNode)
return Type();
auto parentModule = findModule(findModuleNode(definingDecl));
auto parentModule = findModule(moduleNode);
if (!parentModule)
return Type();

Expand Down
7 changes: 7 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2665,3 +2665,10 @@ void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) {
break;
}
}

std::string ASTMangler::mangleOpaqueTypeDescriptor(const OpaqueTypeDecl *decl) {
beginMangling();
appendOpaqueDeclName(decl);
appendOperator("MQ");
return finalize();
}
62 changes: 36 additions & 26 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,14 +826,16 @@ void IRGenModule::addObjCClass(llvm::Constant *classPtr, bool nonlazy) {
ObjCNonLazyClasses.push_back(classPtr);
}

void IRGenModule::addRuntimeResolvableType(NominalTypeDecl *nominal) {
void IRGenModule::addRuntimeResolvableType(GenericTypeDecl *type) {
// Collect the nominal type records we emit into a special section.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you assert that type is an OpaqueTypeDecl or NominalTypeDecl (and not TypeAliasDecl which is the other subclass of GenericTypeDecl), and fix this comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have that assertion deeper in the pipe, when you try to emit a context descriptor.

RuntimeResolvableTypes.push_back(nominal);
RuntimeResolvableTypes.push_back(type);

// As soon as the type metadata is available, all the type's conformances
// must be available, too. The reason is that a type (with the help of its
// metadata) can be checked at runtime if it conforms to a protocol.
addLazyConformances(nominal);
if (auto nominal = dyn_cast<NominalTypeDecl>(type)) {
// As soon as the type metadata is available, all the type's conformances
// must be available, too. The reason is that a type (with the help of its
// metadata) can be checked at runtime if it conforms to a protocol.
addLazyConformances(nominal);
}
}

ConstantReference
Expand Down Expand Up @@ -2744,41 +2746,49 @@ getObjCClassByNameReference(IRGenModule &IGM, ClassDecl *cls) {
SmallString<64> objcRuntimeNameBuffer;
auto ref = IGM.getAddrOfGlobalString(
cls->getObjCRuntimeName(objcRuntimeNameBuffer),
/*willByRelativelyAddressed=*/true);
/*willBeRelativelyAddressed=*/true);

return TypeEntityReference(kind, ref);
}

TypeEntityReference
IRGenModule::getTypeEntityReference(NominalTypeDecl *decl) {
IRGenModule::getTypeEntityReference(GenericTypeDecl *decl) {
if (auto protocol = dyn_cast<ProtocolDecl>(decl)) {
assert(!protocol->isObjC() && "imported protocols not handled here");
return getProtocolDescriptorEntityReference(*this, protocol);
}

auto clas = dyn_cast<ClassDecl>(decl);
if (!clas) {
return getTypeContextDescriptorEntityReference(*this, decl);

if (auto opaque = dyn_cast<OpaqueTypeDecl>(decl)) {
auto entity = LinkEntity::forOpaqueTypeDescriptor(opaque);
IRGen.noteUseOfOpaqueTypeDescriptor(opaque);
return getContextDescriptorEntityReference(*this, entity);
}

switch (clas->getForeignClassKind()) {
case ClassDecl::ForeignKind::RuntimeOnly:
return getObjCClassByNameReference(*this, clas);
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
auto clas = dyn_cast<ClassDecl>(decl);
if (!clas) {
return getTypeContextDescriptorEntityReference(*this, nominal);
}

case ClassDecl::ForeignKind::CFType:
return getTypeContextDescriptorEntityReference(*this, clas);
switch (clas->getForeignClassKind()) {
case ClassDecl::ForeignKind::RuntimeOnly:
return getObjCClassByNameReference(*this, clas);

case ClassDecl::ForeignKind::Normal:
if (hasKnownSwiftMetadata(*this, clas)) {
case ClassDecl::ForeignKind::CFType:
return getTypeContextDescriptorEntityReference(*this, clas);
}

// Note: we would like to use an Objective-C class reference, but the
// Darwin linker currently has a bug where it will coalesce these symbols
// *after* computing a relative offset, causing incorrect relative
// offsets in the metadata. Therefore, reference Objective-C classes by
// their runtime names.
return getObjCClassByNameReference(*this, clas);
case ClassDecl::ForeignKind::Normal:
if (hasKnownSwiftMetadata(*this, clas)) {
return getTypeContextDescriptorEntityReference(*this, clas);
}

// Note: we would like to use an Objective-C class reference, but the
// Darwin linker currently has a bug where it will coalesce these symbols
// *after* computing a relative offset, causing incorrect relative
// offsets in the metadata. Therefore, reference Objective-C classes by
// their runtime names.
return getObjCClassByNameReference(*this, clas);
}
}
llvm_unreachable("bad foreign type kind");
}
Expand Down
Loading