Files
swift-mirror/lib/IRGen/GenReflection.cpp
David Farler 7e8b8f83e8 Emit reflection metadata by default
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.
2016-03-18 17:50:32 -07:00

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;
}