blob: 8e487201f52f97cd7e61893a93e348f2f502ef23 [file] [log] [blame]
//===--- IRGenMangler.cpp - mangling of IRGen symbols ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "IRGenMangler.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/ProtocolAssociations.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/Demangling/Demangle.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/ClangImporter/ClangModule.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace swift;
using namespace irgen;
const char *getManglingForWitness(swift::Demangle::ValueWitnessKind kind) {
switch (kind) {
#define VALUE_WITNESS(MANGLING, NAME) \
case swift::Demangle::ValueWitnessKind::NAME: return #MANGLING;
#include "swift/Demangling/ValueWitnessMangling.def"
}
llvm_unreachable("not a function witness");
}
std::string IRGenMangler::mangleValueWitness(Type type, ValueWitness witness) {
beginMangling();
appendType(type);
const char *Code = nullptr;
switch (witness) {
#define GET_MANGLING(ID) \
case ValueWitness::ID: Code = getManglingForWitness(swift::Demangle::ValueWitnessKind::ID); break;
GET_MANGLING(InitializeBufferWithCopyOfBuffer) \
GET_MANGLING(Destroy) \
GET_MANGLING(InitializeWithCopy) \
GET_MANGLING(AssignWithCopy) \
GET_MANGLING(InitializeWithTake) \
GET_MANGLING(AssignWithTake) \
GET_MANGLING(GetEnumTagSinglePayload) \
GET_MANGLING(StoreEnumTagSinglePayload) \
GET_MANGLING(GetEnumTag) \
GET_MANGLING(DestructiveProjectEnumData) \
GET_MANGLING(DestructiveInjectEnumTag)
#undef GET_MANGLING
case ValueWitness::Size:
case ValueWitness::Flags:
case ValueWitness::ExtraInhabitantCount:
case ValueWitness::Stride:
llvm_unreachable("not a function witness");
}
appendOperator("w", Code);
return finalize();
}
std::string IRGenMangler::manglePartialApplyForwarder(StringRef FuncName) {
if (FuncName.empty()) {
beginMangling();
} else {
if (FuncName.startswith(MANGLING_PREFIX_STR)) {
Buffer << FuncName;
} else {
beginMangling();
appendIdentifier(FuncName);
}
}
appendOperator("TA");
return finalize();
}
SymbolicMangling
IRGenMangler::withSymbolicReferences(IRGenModule &IGM,
llvm::function_ref<void ()> body) {
Mod = IGM.getSwiftModule();
OptimizeProtocolNames = false;
llvm::SaveAndRestore<bool>
AllowSymbolicReferencesLocally(AllowSymbolicReferences);
llvm::SaveAndRestore<std::function<bool (SymbolicReferent)>>
CanSymbolicReferenceLocally(CanSymbolicReference);
AllowSymbolicReferences = true;
CanSymbolicReference = [&IGM](SymbolicReferent s) -> bool {
if (auto type = s.dyn_cast<const NominalTypeDecl *>()) {
// FIXME: Sometimes we fail to emit metadata for Clang imported types
// even after noting use of their type descriptor or metadata. Work
// around by not symbolic-referencing imported types for now.
if (type->hasClangNode())
return false;
// TODO: We ought to be able to use indirect symbolic references even
// when the referent may be in another file, once the on-disk
// ObjectMemoryReader can handle them.
// Private entities are known to be accessible.
if (type->getEffectiveAccess() >= AccessLevel::Internal &&
(!IGM.CurSourceFile ||
IGM.CurSourceFile != type->getParentSourceFile()))
return false;
// @objc protocols don't have descriptors.
if (auto proto = dyn_cast<ProtocolDecl>(type))
if (proto->isObjC())
return false;
return true;
} else {
llvm_unreachable("symbolic referent not handled");
}
};
SymbolicReferences.clear();
body();
return {finalize(), std::move(SymbolicReferences)};
}
SymbolicMangling
IRGenMangler::mangleTypeForReflection(IRGenModule &IGM,
Type Ty) {
return withSymbolicReferences(IGM, [&]{
appendType(Ty);
});
}
std::string IRGenMangler::mangleProtocolConformanceDescriptor(
const RootProtocolConformance *conformance) {
beginMangling();
if (isa<NormalProtocolConformance>(conformance)) {
appendProtocolConformance(conformance);
appendOperator("Mc");
} else {
auto protocol = cast<SelfProtocolConformance>(conformance)->getProtocol();
appendProtocolName(protocol);
appendOperator("MS");
}
return finalize();
}
SymbolicMangling
IRGenMangler::mangleProtocolConformanceForReflection(IRGenModule &IGM,
Type ty, ProtocolConformanceRef conformance) {
return withSymbolicReferences(IGM, [&]{
if (conformance.isConcrete()) {
appendProtocolConformance(conformance.getConcrete());
} else {
// Use a special mangling for abstract conformances.
appendType(ty);
appendProtocolName(conformance.getAbstract());
}
});
}
std::string IRGenMangler::mangleTypeForLLVMTypeName(CanType Ty) {
// To make LLVM IR more readable we always add a 'T' prefix so that type names
// don't start with a digit and don't need to be quoted.
Buffer << 'T';
if (auto P = dyn_cast<ProtocolType>(Ty)) {
appendProtocolName(P->getDecl(), /*allowStandardSubstitution=*/false);
appendOperator("P");
} else {
appendType(Ty);
}
return finalize();
}
std::string IRGenMangler::
mangleProtocolForLLVMTypeName(ProtocolCompositionType *type) {
ExistentialLayout layout = type->getExistentialLayout();
if (type->isAny()) {
Buffer << "Any";
} else if (layout.isAnyObject()) {
Buffer << "AnyObject";
} else {
// To make LLVM IR more readable we always add a 'T' prefix so that type names
// don't start with a digit and don't need to be quoted.
Buffer << 'T';
auto protocols = layout.getProtocols();
for (unsigned i = 0, e = protocols.size(); i != e; ++i) {
appendProtocolName(protocols[i]->getDecl());
if (i == 0)
appendOperator("_");
}
if (auto superclass = layout.explicitSuperclass) {
// We share type infos for different instantiations of a generic type
// when the archetypes have the same exemplars. We cannot mangle
// archetypes, and the mangling does not have to be unique, so we just
// mangle the unbound generic form of the type.
if (superclass->hasArchetype()) {
superclass = superclass->getClassOrBoundGenericClass()
->getDeclaredType();
}
appendType(CanType(superclass));
appendOperator("Xc");
} else if (layout.getLayoutConstraint()) {
appendOperator("Xl");
} else {
appendOperator("p");
}
}
return finalize();
}
std::string IRGenMangler::
mangleSymbolNameForSymbolicMangling(const SymbolicMangling &mangling,
MangledTypeRefRole role) {
beginManglingWithoutPrefix();
const char *prefix;
switch (role) {
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
prefix = "default assoc type ";
break;
case MangledTypeRefRole::Metadata:
case MangledTypeRefRole::Reflection:
prefix = "symbolic ";
break;
}
auto prefixLen = strlen(prefix);
Buffer << prefix << mangling.String;
for (auto &symbol : mangling.SymbolicReferences) {
// Fill in the placeholder space with something printable.
auto referent = symbol.first;
auto offset = symbol.second;
Storage[prefixLen + offset]
= Storage[prefixLen + offset+1]
= Storage[prefixLen + offset+2]
= Storage[prefixLen + offset+3]
= Storage[prefixLen + offset+4]
= '_';
Buffer << ' ';
if (auto ty = referent.dyn_cast<const NominalTypeDecl*>())
appendContext(ty);
else
llvm_unreachable("unhandled referent");
}
return finalize();
}
std::string IRGenMangler::mangleSymbolNameForAssociatedConformanceWitness(
const NormalProtocolConformance *conformance,
CanType associatedType,
const ProtocolDecl *proto) {
beginManglingWithoutPrefix();
if (conformance) {
Buffer << "associated conformance ";
appendProtocolConformance(conformance);
} else {
Buffer << "default associated conformance";
}
bool isFirstAssociatedTypeIdentifier = true;
appendAssociatedTypePath(associatedType, isFirstAssociatedTypeIdentifier);
appendProtocolName(proto);
return finalize();
}
std::string IRGenMangler::mangleSymbolNameForKeyPathMetadata(
const char *kind,
CanGenericSignature genericSig,
CanType type,
ProtocolConformanceRef conformance) {
beginManglingWithoutPrefix();
Buffer << kind << " ";
if (genericSig)
appendGenericSignature(genericSig);
if (type)
appendType(type);
if (conformance.isConcrete())
appendConcreteProtocolConformance(conformance.getConcrete());
else if (conformance.isAbstract())
appendProtocolName(conformance.getAbstract());
else
assert(conformance.isInvalid() && "Unknown protocol conformance");
return finalize();
}
std::string IRGenMangler::mangleSymbolNameForGenericEnvironment(
CanGenericSignature genericSig) {
beginManglingWithoutPrefix();
Buffer << "generic environment ";
appendGenericSignature(genericSig);
return finalize();
}