mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This turns on the remote reflection metadata by default for swift invocations and the standard library. The size delta for all of the sections is: Section __swift3_typeref: 20176 Section __swift3_reflstr: 2556 Section __swift3_fieldmd: 8172 Section __swift3_assocty: 18112 Recognizing that this is a nontrivial increase in binary size, we can reduce this with a few methods: - Trie for strings (typerefs and field names are both strings) but would need an implementation - Compress the entire sections: this would need an implementation available on all platforms where we support the functionality. - Don't use the AST mangler but a custom mangling, which may be slightly more compact because it can specialize by need and maybe not include some mangle nodes that typerefs don't need.
301 lines
9.5 KiB
C++
301 lines
9.5 KiB
C++
//===--- GenReflection.cpp - IR generation for nominal type reflection ----===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements IR generation of type metadata for struct/class
|
|
// stored properties and enum cases for use with reflection.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/AST/ArchetypeBuilder.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/IRGenOptions.h"
|
|
#include "swift/AST/PrettyStackTrace.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/Reflection/Records.h"
|
|
|
|
#include "ConstantBuilder.h"
|
|
#include "IRGenModule.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
class ReflectionMetadataBuilder : public ConstantBuilder<> {
|
|
protected:
|
|
void addTypeRef(Module *ModuleContext, CanType type) {
|
|
Mangle::Mangler mangler(/*DWARFMangling*/false,
|
|
/*usePunyCode*/ true,
|
|
/*OptimizeProtocolNames*/ false);
|
|
mangler.setModuleContext(ModuleContext);
|
|
mangler.mangleType(type, 0);
|
|
auto mangledName = IGM.getAddrOfStringForTypeRef(mangler.finalize());
|
|
addRelativeAddress(mangledName);
|
|
}
|
|
|
|
public:
|
|
ReflectionMetadataBuilder(IRGenModule &IGM) : ConstantBuilder(IGM) {}
|
|
};
|
|
|
|
class AssociatedTypeMetadataBuilder : public ReflectionMetadataBuilder {
|
|
static const uint32_t AssociatedTypeRecordSize = 8;
|
|
ArrayRef<const NominalTypeDecl *> NominalTypeDecls;
|
|
|
|
void addDecl(const NominalTypeDecl *decl) {
|
|
PrettyStackTraceDecl DebugStack("emitting associated type metadata", decl);
|
|
for (auto Conformance : decl->getAllConformances()) {
|
|
SmallVector<std::pair<StringRef, CanType>, 2> AssociatedTypes;
|
|
|
|
auto collectTypeWitness = [&](const AssociatedTypeDecl *AssocTy,
|
|
const Substitution &Sub,
|
|
const TypeDecl *TD) -> bool {
|
|
|
|
auto Subst = ArchetypeBuilder::mapTypeOutOfContext(
|
|
Conformance->getDeclContext(), Sub.getReplacement());
|
|
|
|
AssociatedTypes.push_back({
|
|
AssocTy->getNameStr(),
|
|
Subst->getCanonicalType()
|
|
});
|
|
return false;
|
|
};
|
|
|
|
auto ModuleContext = decl->getModuleContext();
|
|
addTypeRef(ModuleContext, decl->getDeclaredType()->getCanonicalType());
|
|
|
|
auto ProtoTy = Conformance->getProtocol()->getDeclaredType();
|
|
addTypeRef(ModuleContext, ProtoTy->getCanonicalType());
|
|
|
|
Conformance->forEachTypeWitness(/*resolver*/ nullptr, collectTypeWitness);
|
|
|
|
addConstantInt32(AssociatedTypes.size());
|
|
addConstantInt32(AssociatedTypeRecordSize);
|
|
|
|
for (auto AssocTy : AssociatedTypes) {
|
|
auto NameGlobal = IGM.getAddrOfStringForTypeRef(AssocTy.first);
|
|
addRelativeAddress(NameGlobal);
|
|
addTypeRef(ModuleContext, AssocTy.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
public:
|
|
AssociatedTypeMetadataBuilder(IRGenModule &IGM,
|
|
ArrayRef<const NominalTypeDecl *> NominalTypeDecls)
|
|
: ReflectionMetadataBuilder(IGM), NominalTypeDecls(NominalTypeDecls) {}
|
|
|
|
void layout() {
|
|
for (auto decl : NominalTypeDecls)
|
|
addDecl(decl);
|
|
}
|
|
|
|
llvm::GlobalVariable *emit() {
|
|
auto tempBase = std::unique_ptr<llvm::GlobalVariable>(
|
|
new llvm::GlobalVariable(IGM.Int8Ty, /*isConstant*/ true,
|
|
llvm::GlobalValue::PrivateLinkage));
|
|
setRelativeAddressBase(tempBase.get());
|
|
|
|
layout();
|
|
auto init = getInit();
|
|
if (!init)
|
|
return nullptr;
|
|
|
|
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
|
|
/*isConstant*/ true,
|
|
llvm::GlobalValue::PrivateLinkage,
|
|
init,
|
|
"\x01l__swift3_assocty_metadata");
|
|
var->setSection(IGM.getAssociatedTypeMetadataSectionName());
|
|
var->setAlignment(IGM.getPointerAlignment().getValue());
|
|
|
|
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
|
|
tempBase->replaceAllUsesWith(replacer);
|
|
|
|
return var;
|
|
}
|
|
};
|
|
|
|
class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
|
|
|
|
const uint32_t fieldRecordSize = 12;
|
|
ArrayRef<const NominalTypeDecl *> NominalTypeDecls;
|
|
|
|
void addFieldDecl(const ValueDecl *value) {
|
|
swift::reflection::FieldRecordFlags Flags;
|
|
Flags.setIsObjC(value->isObjC());
|
|
|
|
addConstantInt32(Flags.getRawValue());
|
|
|
|
auto type = value->getInterfaceType()->getCanonicalType();
|
|
addTypeRef(value->getModuleContext(), type);
|
|
|
|
if (IGM.Opts.StripReflectionNames) {
|
|
addConstantInt32(0);
|
|
} else {
|
|
auto fieldName = IGM.getAddrOfFieldName(value->getNameStr());
|
|
addRelativeAddress(fieldName);
|
|
}
|
|
}
|
|
|
|
void addDecl(const NominalTypeDecl *decl) {
|
|
PrettyStackTraceDecl DebugStack("emitting field type metadata", decl);
|
|
auto type = decl->getDeclaredType()->getCanonicalType();
|
|
addTypeRef(decl->getModuleContext(), type);
|
|
|
|
switch (decl->getKind()) {
|
|
case DeclKind::Class:
|
|
case DeclKind::Struct: {
|
|
auto properties = decl->getStoredProperties();
|
|
addConstantInt32(std::distance(properties.begin(), properties.end()));
|
|
addConstantInt32(fieldRecordSize);
|
|
for (auto property : properties)
|
|
addFieldDecl(property);
|
|
break;
|
|
}
|
|
case DeclKind::Enum: {
|
|
auto enumDecl = cast<EnumDecl>(decl);
|
|
auto cases = enumDecl->getAllElements();
|
|
addConstantInt32(std::distance(cases.begin(), cases.end()));
|
|
addConstantInt32(fieldRecordSize);
|
|
for (auto enumCase : cases)
|
|
addFieldDecl(enumCase);
|
|
break;
|
|
}
|
|
default:
|
|
llvm_unreachable("Not a nominal type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
public:
|
|
FieldTypeMetadataBuilder(IRGenModule &IGM,
|
|
ArrayRef<const NominalTypeDecl *> NominalTypeDecls)
|
|
: ReflectionMetadataBuilder(IGM), NominalTypeDecls(NominalTypeDecls) {}
|
|
void layout() {
|
|
for (auto decl : NominalTypeDecls) {
|
|
addDecl(decl);
|
|
}
|
|
}
|
|
|
|
llvm::GlobalVariable *emit() {
|
|
|
|
auto tempBase = std::unique_ptr<llvm::GlobalVariable>(
|
|
new llvm::GlobalVariable(IGM.Int8Ty, /*isConstant*/ true,
|
|
llvm::GlobalValue::PrivateLinkage));
|
|
setRelativeAddressBase(tempBase.get());
|
|
|
|
layout();
|
|
auto init = getInit();
|
|
|
|
if (!init)
|
|
return nullptr;
|
|
|
|
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
|
|
/*isConstant*/ true,
|
|
llvm::GlobalValue::PrivateLinkage,
|
|
init,
|
|
"\x01l__swift3_reflection_metadata");
|
|
var->setSection(IGM.getFieldTypeMetadataSectionName());
|
|
var->setAlignment(IGM.getPointerAlignment().getValue());
|
|
|
|
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
|
|
tempBase->replaceAllUsesWith(replacer);
|
|
|
|
return var;
|
|
}
|
|
};
|
|
|
|
static std::string getReflectionSectionName(IRGenModule &IGM,
|
|
std::string Base) {
|
|
SmallString<50> SectionName;
|
|
llvm::raw_svector_ostream OS(SectionName);
|
|
switch (IGM.TargetInfo.OutputObjectFormat) {
|
|
case llvm::Triple::MachO:
|
|
assert(Base.size() <= 7
|
|
&& "Mach-O section name length must be <= 16 characters");
|
|
OS << "__DATA, __swift3_" << Base << ", regular, no_dead_strip";
|
|
break;
|
|
case llvm::Triple::ELF:
|
|
OS << ".swift3_" << Base;
|
|
break;
|
|
default:
|
|
llvm_unreachable("Don't know how to emit field name table for "
|
|
"the selected object format.");
|
|
}
|
|
return OS.str();
|
|
}
|
|
|
|
std::string IRGenModule::getFieldTypeMetadataSectionName() {
|
|
return getReflectionSectionName(*this, "fieldmd");
|
|
}
|
|
|
|
std::string IRGenModule::getAssociatedTypeMetadataSectionName() {
|
|
return getReflectionSectionName(*this, "assocty");
|
|
}
|
|
|
|
std::string IRGenModule::getReflectionStringsSectionName() {
|
|
return getReflectionSectionName(*this, "reflstr");
|
|
}
|
|
|
|
std::string IRGenModule::getReflectionTypeRefSectionName() {
|
|
return getReflectionSectionName(*this, "typeref");
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getAddrOfFieldName(StringRef Name) {
|
|
auto &entry = FieldNames[Name];
|
|
if (entry.second)
|
|
return entry.second;
|
|
|
|
entry = createStringConstant(Name, /*willBeRelativelyAddressed*/ true,
|
|
getReflectionStringsSectionName());
|
|
return entry.second;
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getAddrOfStringForTypeRef(StringRef Str) {
|
|
auto &entry = StringsForTypeRef[Str];
|
|
if (entry.second)
|
|
return entry.second;
|
|
|
|
entry = createStringConstant(Str, /*willBeRelativelyAddressed*/ true,
|
|
getReflectionTypeRefSectionName());
|
|
return entry.second;
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::emitFieldTypeMetadataRecords() {
|
|
if (Opts.StripReflectionMetadata)
|
|
return nullptr;
|
|
|
|
if (NominalTypeDecls.empty())
|
|
return nullptr;
|
|
|
|
FieldTypeMetadataBuilder builder(*this, NominalTypeDecls);
|
|
auto var = builder.emit();
|
|
if (!var)
|
|
return nullptr;
|
|
|
|
addUsedGlobal(var);
|
|
return var;
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::emitAssociatedTypeMetadataRecords() {
|
|
if (Opts.StripReflectionMetadata)
|
|
return nullptr;
|
|
|
|
if (NominalTypeDecls.empty())
|
|
return nullptr;
|
|
|
|
AssociatedTypeMetadataBuilder builder(*this, NominalTypeDecls);
|
|
auto var = builder.emit();
|
|
if (!var)
|
|
return nullptr;
|
|
|
|
addUsedGlobal(var);
|
|
return var;
|
|
}
|