Skip to content

Commit

Permalink
Decode opaque types in the runtime demangler.
Browse files Browse the repository at this point in the history
  • Loading branch information
jckarter committed Mar 15, 2019
1 parent c921968 commit 88a05b7
Show file tree
Hide file tree
Showing 17 changed files with 376 additions and 158 deletions.
39 changes: 21 additions & 18 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,13 @@ The following symbolic reference kinds are currently implemented:

::

{any-generic-type, protocol} ::= '\x01' .{4} // Reference points directly to context descriptor
{any-generic-type, protocol} ::= '\x02' .{4} // Reference points indirectly to context descriptor
#if SWIFT_RUNTIME_VERSION < 5.1
{any-generic-type, protocol} ::= '\x01' .{4} // Reference points directly to context descriptor
{any-generic-type, protocol} ::= '\x02' .{4} // Reference points indirectly to context descriptor
#else
{any-generic-type, protocol, opaque-type-decl-name} ::= '\x01' .{4} // Reference points directly to context descriptor
{any-generic-type, protocol, opaque-type-decl-name} ::= '\x02' .{4} // Reference points indirectly to context descriptor
#endif
// The grammatical role of the symbolic reference is determined by the
// kind of context descriptor referenced

Expand All @@ -93,15 +98,13 @@ The following symbolic reference kinds are currently implemented:
associated-conformance-access-function ::= '\x08' .{4} // Reference points directly to associated conformance access function relative to the conforming type

// keypaths only in Swift 5.0, generalized in Swift 5.1
metadata-access-function ::= '\x09' .{4} // Reference points directly to metadata access function that can be invoked to produce referenced object

// begin added in Swift 5.1
any-generic-type ::= '\x0B' .{4} // Reference points directly to an opaque type descriptor
any-generic-type ::= '\x0C' .{4} // Reference points indirectly to an opaque type descriptor
// end added in Swift 5.1
#if SWIFT_RUNTIME_VERSION >= 5.1
metadata-access-function ::= '\x09' .{4} // Reference points directly to metadata access function that can be invoked to produce referenced object
#endif

A mangled name may also include ``\xFF`` bytes, which are only used for alignment
padding. They can be skipped over and ignored.
A mangled name may also include ``\xFF`` bytes, which are only used for
alignment padding. They do not affect what the mangled name references and can
be skipped over and ignored.

Globals
~~~~~~~
Expand All @@ -120,7 +123,9 @@ Globals
global ::= nominal-type 'Ml' // in-place type initialization cache
global ::= nominal-type 'Mm' // class metaclass
global ::= nominal-type 'Mn' // nominal type descriptor
global ::= opaque-type-decl-name 'MQ' // opaque type descriptor -- added in Swift 5.1
#if SWIFT_RUNTIME_VERSION >= 5.1
global ::= opaque-type-decl-name 'MQ' // opaque type descriptor -- added in Swift 5.1
#endif
global ::= nominal-type 'Mu' // class method lookup function
global ::= nominal-type 'MU' // ObjC metadata update callback function
global ::= module 'MXM' // module descriptor
Expand Down Expand Up @@ -609,14 +614,12 @@ implementation details of a function type.

::

// begin added in Swift 5.1

type ::= 'Qr' // opaque result type (of current decl)
type ::= opaque-type-decl-name bound-generic-args 'Qo' // opaque type

opaque-type-decl-name ::= entity 'QO' // opaque result type of specified decl
#if SWIFT_VERSION >= 5.1
type ::= 'Qr' // opaque result type (of current decl)
type ::= opaque-type-decl-name bound-generic-args 'Qo' INDEX // opaque type

// end added in Swift 5.1
opaque-type-decl-name ::= entity 'QO' // opaque result type of specified decl
#endif

Opaque return types have a special short representation in the mangling of
their defining entity. In structural position, opaque types are fully qualified
Expand Down
17 changes: 15 additions & 2 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -3002,6 +3002,11 @@ struct TargetOpaqueTypeDescriptor final
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;

public:
using TrailingGenericContextObjects::getGenericContext;
using TrailingGenericContextObjects::getGenericContextHeader;
using TrailingGenericContextObjects::getFullGenericContextHeader;
using TrailingGenericContextObjects::getGenericParams;

// The kind-specific flags area is used to store the count of the generic
// arguments for underlying type(s) encoded in the descriptor.
unsigned getNumUnderlyingTypeArguments() const {
Expand All @@ -3013,9 +3018,12 @@ struct TargetOpaqueTypeDescriptor final
return getNumUnderlyingTypeArguments();
}

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

return Demangle::makeSymbolicMangledNameStringRef(ptr);
}

static bool classof(const TargetContextDescriptor<Runtime> *cd) {
Expand Down Expand Up @@ -4183,6 +4191,9 @@ TargetContextDescriptor<Runtime>::getGenericContext() const {
case ContextDescriptorKind::Struct:
return llvm::cast<TargetStructDescriptor<Runtime>>(this)
->getGenericContext();
case ContextDescriptorKind::OpaqueType:
return llvm::cast<TargetOpaqueTypeDescriptor<Runtime>>(this)
->getGenericContext();
default:
// We don't know about this kind of descriptor.
return nullptr;
Expand Down Expand Up @@ -4234,6 +4245,8 @@ TargetTypeContextDescriptor<Runtime>::getGenericParams() const {
return llvm::cast<TargetEnumDescriptor<Runtime>>(this)->getGenericParams();
case ContextDescriptorKind::Struct:
return llvm::cast<TargetStructDescriptor<Runtime>>(this)->getGenericParams();
case ContextDescriptorKind::OpaqueType:
return llvm::cast<TargetOpaqueTypeDescriptor<Runtime>>(this)->getGenericParams();
default:
swift_runtime_unreachable("Not a type context descriptor.");
}
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/ASTDemangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ class ASTBuilder {
Type createTypeAliasType(GenericTypeDecl *decl, Type parent);

Type createBoundGenericType(GenericTypeDecl *decl, ArrayRef<Type> args);

Type resolveOpaqueType(NodePointer opaqueDescriptor,
ArrayRef<Type> args,
unsigned ordinal);

Type createBoundGenericType(GenericTypeDecl *decl, ArrayRef<Type> args,
Type parent);
Expand Down
13 changes: 10 additions & 3 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,18 @@ class ASTMangler : public Mangler {

public:
using SymbolicReferent = llvm::PointerUnion<const NominalTypeDecl *,
const ProtocolConformance *>;
const OpaqueTypeDecl *>;
protected:

/// If set, the mangler calls this function to determine whether to symbolic
/// reference a given entity. Defaults to always returning true.
/// reference a given entity. If null, the mangler acts as if it's set to
/// always return true.
std::function<bool (SymbolicReferent)> CanSymbolicReference;

bool canSymbolicReference(SymbolicReferent referent) {
return AllowSymbolicReferences
&& (!CanSymbolicReference || CanSymbolicReference(referent));
}

std::vector<std::pair<SymbolicReferent, unsigned>> SymbolicReferences;

Expand Down Expand Up @@ -236,7 +242,8 @@ class ASTMangler : public Mangler {

/// Append any retroactive conformances.
void appendRetroactiveConformances(Type type);

void appendRetroactiveConformances(SubstitutionMap subMap,
ModuleDecl *fromModule);
void appendImplFunctionType(SILFunctionType *fn);

void appendContextOf(const ValueDecl *decl);
Expand Down
3 changes: 2 additions & 1 deletion include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -259,11 +259,12 @@ NODE(SugaredDictionary)
NODE(SugaredParen)

// Added in Swift 5.1
NODE(AccessorFunctionReference)
NODE(OpaqueType)
NODE(OpaqueTypeDescriptorSymbolicReference)
NODE(OpaqueTypeDescriptor)
NODE(OpaqueReturnType)
NODE(OpaqueReturnTypeOf)
NODE(AccessorFunctionReference)

#undef CONTEXT_NODE
#undef NODE
3 changes: 3 additions & 0 deletions include/swift/Demangling/Demangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,9 @@ class Demangler : public NodeFactory {
NodePointer demangleSymbolicReference(unsigned char rawKind,
const void *at);

bool demangleBoundGenerics(Vector<NodePointer> &TypeListList,
NodePointer &RetroactiveConformances);

void dump();

public:
Expand Down
32 changes: 31 additions & 1 deletion include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,8 @@ class TypeDecoder {
std::vector<BuiltType> args;

const auto &genericArgs = Node->getChild(1);
assert(genericArgs->getKind() == NodeKind::TypeList);
if (genericArgs->getKind() != NodeKind::TypeList)
return BuiltType();

for (auto genericArg : *genericArgs) {
auto paramType = decodeMangledType(genericArg);
Expand Down Expand Up @@ -777,6 +778,35 @@ class TypeDecoder {

return Builder.createParenType(base);
}
case NodeKind::OpaqueType: {
if (Node->getNumChildren() < 3)
return BuiltType();
auto descriptor = Node->getChild(0);
auto ordinalNode = Node->getChild(1);

if (ordinalNode->getKind() != NodeKind::Index
|| !ordinalNode->hasIndex())
return BuiltType();
auto ordinal = ordinalNode->getIndex();

std::vector<BuiltType> genericArgs;
auto boundGenerics = Node->getChild(2);
for (unsigned i = 0; i < boundGenerics->getNumChildren(); ++i) {
auto genericsNode = boundGenerics->getChild(i);
if (genericsNode->getKind() != NodeKind::TypeList)
break;
for (auto argNode : *genericsNode) {
auto arg = decodeMangledType(argNode);
if (!arg)
return BuiltType();
genericArgs.push_back(arg);
}
}

return Builder.resolveOpaqueType(descriptor, genericArgs, ordinal);
}
// TODO: Handle OpaqueReturnType, when we're in the middle of reconstructing
// the defining decl
default:
return BuiltType();
}
Expand Down
8 changes: 8 additions & 0 deletions include/swift/Reflection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,14 @@ class TypeRefBuilder {
const TypeRef *parent) {
return BoundGenericTypeRef::create(*this, *mangledName, args, parent);
}

const TypeRef *
resolveOpaqueType(NodePointer opaqueDescriptor,
const std::vector<const TypeRef *> &genericArgs,
unsigned ordinal) {
// TODO
return nullptr;
}

const TupleTypeRef *
createTupleType(const std::vector<const TypeRef *> &elements,
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@ Type ASTBuilder::createBoundGenericType(GenericTypeDecl *decl,
return substType;
}

Type ASTBuilder::resolveOpaqueType(NodePointer opaqueDescriptor,
ArrayRef<Type> args,
unsigned ordinal) {
// TODO
return Type();
}

Type ASTBuilder::createBoundGenericType(GenericTypeDecl *decl,
ArrayRef<Type> args,
Type parent) {
Expand Down
78 changes: 46 additions & 32 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,9 @@ static bool shouldMangleAsGeneric(Type type) {
}

void ASTMangler::appendOpaqueDeclName(const OpaqueTypeDecl *opaqueDecl) {
if (auto namingDecl = opaqueDecl->getNamingDecl()) {
if (canSymbolicReference(opaqueDecl)) {
appendSymbolicReference(opaqueDecl);
} else if (auto namingDecl = opaqueDecl->getNamingDecl()) {
appendEntity(namingDecl);
appendOperator("QO");
} else {
Expand Down Expand Up @@ -968,13 +970,24 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) {
}
}

// Otherwise, use the fully qualified mangling.
// Otherwise, try to substitute it.
if (tryMangleTypeSubstitution(type))
return;

// Use the fully elaborated explicit mangling.
appendOpaqueDeclName(opaqueDecl);
bool isFirstArgList = true;
appendBoundGenericArgs(opaqueDecl->getInnermostDeclContext(),
opaqueType->getSubstitutions(),
isFirstArgList);
appendOperator("Qo");
appendRetroactiveConformances(opaqueType->getSubstitutions(),
opaqueDecl->getParentModule());

// TODO: If we support multiple opaque types in a return, put the
// ordinal for this archetype here.
appendOperator("Qo", Index(0));

addTypeSubstitution(type);
return;
}

Expand Down Expand Up @@ -1289,24 +1302,8 @@ static bool containsRetroactiveConformance(
return false;
}

void ASTMangler::appendRetroactiveConformances(Type type) {
// Dig out the substitution map to use.
SubstitutionMap subMap;
ModuleDecl *module;
if (auto typeAlias = dyn_cast<TypeAliasType>(type.getPointer())) {
module = Mod ? Mod : typeAlias->getDecl()->getModuleContext();
subMap = typeAlias->getSubstitutionMap();
} else {
if (type->hasUnboundGenericType())
return;

auto nominal = type->getAnyNominal();
if (!nominal) return;

module = Mod ? Mod : nominal->getModuleContext();
subMap = type->getContextSubstitutionMap(module, nominal);
}

void ASTMangler::appendRetroactiveConformances(SubstitutionMap subMap,
ModuleDecl *fromModule) {
if (subMap.empty()) return;

unsigned numProtocolRequirements = 0;
Expand All @@ -1320,14 +1317,35 @@ void ASTMangler::appendRetroactiveConformances(Type type) {
continue;

// Skip non-retroactive conformances.
if (!containsRetroactiveConformance(conformance.getConcrete(), module))
if (!containsRetroactiveConformance(conformance.getConcrete(), fromModule))
continue;

appendConcreteProtocolConformance(conformance.getConcrete());
appendOperator("g", Index(numProtocolRequirements));
}
}

void ASTMangler::appendRetroactiveConformances(Type type) {
// Dig out the substitution map to use.
SubstitutionMap subMap;
ModuleDecl *module;
if (auto typeAlias = dyn_cast<TypeAliasType>(type.getPointer())) {
module = Mod ? Mod : typeAlias->getDecl()->getModuleContext();
subMap = typeAlias->getSubstitutionMap();
} else {
if (type->hasUnboundGenericType())
return;

auto nominal = type->getAnyNominal();
if (!nominal) return;

module = Mod ? Mod : nominal->getModuleContext();
subMap = type->getContextSubstitutionMap(module, nominal);
}

appendRetroactiveConformances(subMap, module);
}

static char getParamConvention(ParameterConvention conv) {
// @in and @out are mangled the same because they're put in
// different places.
Expand Down Expand Up @@ -1692,8 +1710,7 @@ void ASTMangler::appendProtocolName(const ProtocolDecl *protocol,
return;

// We can use a symbolic reference if they're allowed in this context.
if (AllowSymbolicReferences
&& (!CanSymbolicReference || CanSymbolicReference(protocol))) {
if (canSymbolicReference(protocol)) {
// Try to use a symbolic reference substitution.
if (tryMangleSubstitution(protocol))
return;
Expand Down Expand Up @@ -1753,16 +1770,13 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
if (tryMangleSubstitution(cast<TypeAliasDecl>(decl)))
return;
}


// Try to mangle a symbolic reference for a nominal type.
if (AllowSymbolicReferences) {
if (nominal && (!CanSymbolicReference || CanSymbolicReference(nominal))) {
appendSymbolicReference(nominal);
// Substitutions can refer back to the symbolic reference.
addTypeSubstitution(nominal->getDeclaredType());
return;
}
if (nominal && canSymbolicReference(nominal)) {
appendSymbolicReference(nominal);
// Substitutions can refer back to the symbolic reference.
addTypeSubstitution(nominal->getDeclaredType());
return;
}

appendContextOf(decl);
Expand Down
Loading

0 comments on commit 88a05b7

Please sign in to comment.