Merge pull request #13926 from xedin/rdar-26060144
[Runtime/ABI] Replace `emitTypeFieldAccessor` with a single runtime method
diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h
index 7b21afb..d2bd7dd 100644
--- a/include/swift/Demangling/TypeDecoder.h
+++ b/include/swift/Demangling/TypeDecoder.h
@@ -124,7 +124,8 @@
}
case NodeKind::BoundGenericClass:
case NodeKind::BoundGenericEnum:
- case NodeKind::BoundGenericStructure: {
+ case NodeKind::BoundGenericStructure:
+ case NodeKind::BoundGenericOtherNominalType: {
if (Node->getNumChildren() != 2)
return BuiltType();
diff --git a/include/swift/Reflection/Records.h b/include/swift/Reflection/Records.h
index e2c3354..2bda25a 100644
--- a/include/swift/Reflection/Records.h
+++ b/include/swift/Reflection/Records.h
@@ -19,6 +19,7 @@
#include "swift/Basic/RelativePointer.h"
#include "swift/Demangling/Demangle.h"
+#include "llvm/ADT/ArrayRef.h"
const uint16_t SWIFT_REFLECTION_METADATA_VERSION = 3; // superclass field
@@ -204,6 +205,10 @@
return const_iterator { End, End };
}
+ llvm::ArrayRef<FieldRecord> getFields() const {
+ return {getFieldRecordBuffer(), NumFields};
+ }
+
bool hasMangledTypeName() const {
return MangledTypeName;
}
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index 948dd54..3501251 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -37,11 +37,13 @@
#include "swift/Basic/RelativePointer.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Demangling/ManglingMacros.h"
+#include "swift/Reflection/Records.h"
#include "swift/Runtime/Unreachable.h"
#include "../../../stdlib/public/SwiftShims/HeapObject.h"
#if SWIFT_OBJC_INTEROP
#include <objc/runtime.h>
#endif
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
namespace swift {
@@ -1287,16 +1289,6 @@
auto asWords = reinterpret_cast<const void * const*>(this);
return reinterpret_cast<const StoredPointer *>(asWords + offset);
}
-
- /// Get a pointer to the field type vector, if present, or null.
- const FieldType *getFieldTypes() const {
- assert(isTypeMetadata());
- auto *getter = getDescription()->GetFieldTypes.get();
- if (!getter)
- return nullptr;
-
- return getter(this);
- }
uint32_t getSizeInWords() const {
assert(isTypeMetadata());
@@ -1569,15 +1561,6 @@
auto asWords = reinterpret_cast<const void * const*>(this);
return reinterpret_cast<const StoredPointer *>(asWords + offset);
}
-
- /// Get a pointer to the field type vector, if present, or null.
- const FieldType *getFieldTypes() const {
- auto *getter = getDescription()->GetFieldTypes.get();
- if (!getter)
- return nullptr;
-
- return getter(this);
- }
static bool classof(const TargetMetadata<Runtime> *metadata) {
return metadata->getKind() == MetadataKind::Struct;
@@ -2531,6 +2514,12 @@
/// context is not generic.
const TargetGenericContext<Runtime> *getGenericContext() const;
+ unsigned getNumGenericParams() const {
+ auto *genericContext = getGenericContext();
+ return genericContext
+ ? genericContext->getGenericContextHeader().NumParams
+ : 0;
+ }
private:
TargetContextDescriptor(const TargetContextDescriptor &) = delete;
TargetContextDescriptor(TargetContextDescriptor &&) = delete;
@@ -3165,15 +3154,11 @@
}
public:
- /// The field names. A doubly-null-terminated list of strings, whose
- /// length and order is consistent with that of the field offset vector.
- RelativeDirectPointer<const char, /*nullable*/ true> FieldNames;
-
- /// The field type vector accessor. Returns a pointer to an array of
- /// type metadata references whose order is consistent with that of the
- /// field offset vector.
- RelativeDirectPointer<const FieldType *
- (const TargetMetadata<Runtime> *)> GetFieldTypes;
+ /// Indicates if the type represented by this descriptor
+ /// supports reflection (C and Obj-C enums currently don't).
+ /// FIXME: This is temporarily left as 32-bit integer to avoid
+ /// changing layout of context descriptor.
+ uint32_t IsReflectable;
/// True if metadata records for this type have a field offset vector for
/// its stored properties.
@@ -3275,15 +3260,11 @@
/// vector.
uint32_t FieldOffsetVectorOffset;
- /// The field names. A doubly-null-terminated list of strings, whose
- /// length and order is consistent with that of the field offset vector.
- RelativeDirectPointer<const char, /*nullable*/ true> FieldNames;
-
- /// The field type vector accessor. Returns a pointer to an array of
- /// type metadata references whose order is consistent with that of the
- /// field offset vector.
- RelativeDirectPointer<const FieldType *
- (const TargetMetadata<Runtime> *)> GetFieldTypes;
+ /// Indicates if the type represented by this descriptor
+ /// supports reflection (C and Obj-C enums currently don't).
+ /// FIXME: This is temporarily left as 32-bit integer to avoid
+ /// changing layout of context descriptor.
+ uint32_t IsReflectable;
/// True if metadata records for this type have a field offset vector for
/// its stored properties.
@@ -3327,17 +3308,11 @@
/// The number of empty cases in the enum.
uint32_t NumEmptyCases;
- /// The names of the cases. A doubly-null-terminated list of strings,
- /// whose length is NumNonEmptyCases + NumEmptyCases. Cases are named in
- /// tag order, non-empty cases first, followed by empty cases.
- RelativeDirectPointer<const char, /*nullable*/ true> CaseNames;
-
- /// The field type vector accessor. Returns a pointer to an array of
- /// type metadata references whose order is consistent with that of the
- /// CaseNames. Only types for payload cases are provided.
- RelativeDirectPointer<
- const FieldType * (const TargetMetadata<Runtime> *)>
- GetCaseTypes;
+ /// Indicates if the type represented by this descriptor
+ /// supports reflection (C and Obj-C enums currently don't).
+ /// FIXME: This is temporarily left as 32-bit integer to avoid
+ /// changing layout of context descriptor.
+ uint32_t IsReflectable;
uint32_t getNumPayloadCases() const {
return NumPayloadCasesAndPayloadSizeOffset & 0x00FFFFFFU;
@@ -3760,12 +3735,22 @@
void swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin,
const TypeMetadataRecord *end);
+/// Register a block of type field records for dynamic lookup.
+SWIFT_RUNTIME_EXPORT
+void swift_registerFieldDescriptors(const reflection::FieldDescriptor **records,
+ size_t size);
+
/// Return the superclass, if any. The result is nullptr for root
/// classes and class protocol types.
SWIFT_CC(swift)
SWIFT_RUNTIME_STDLIB_INTERFACE
const Metadata *_swift_class_getSuperclass(const Metadata *theClass);
+SWIFT_RUNTIME_STDLIB_INTERFACE
+void swift_getFieldAt(
+ const Metadata *type, unsigned index,
+ std::function<void(llvm::StringRef name, FieldType type)> callback);
+
} // end namespace swift
#pragma clang diagnostic pop
diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def
index 735902a..56de9d7 100644
--- a/include/swift/Runtime/RuntimeFunctions.def
+++ b/include/swift/Runtime/RuntimeFunctions.def
@@ -1198,6 +1198,11 @@
RETURNS(VoidTy),
ARGS(TypeMetadataRecordPtrTy, TypeMetadataRecordPtrTy),
ATTRS(NoUnwind))
+FUNCTION(RegisterFieldDescriptors,
+ swift_registerFieldDescriptors, DefaultCC,
+ RETURNS(VoidTy),
+ ARGS(FieldDescriptorPtrPtrTy, SizeTy),
+ ATTRS(NoUnwind))
// void swift_beginAccess(void *pointer, ValueBuffer *scratch, size_t flags);
FUNCTION(BeginAccess, swift_beginAccess, C_CC,
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index 893a470..b8d905a 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -65,7 +65,10 @@
case Node::Kind::Class:
case Node::Kind::Enum:
case Node::Kind::Protocol:
+ case Node::Kind::OtherNominalType:
case Node::Kind::TypeAlias:
+ case Node::Kind::SymbolicReference:
+ case Node::Kind::UnresolvedSymbolicReference:
return true;
default:
return false;
@@ -1237,11 +1240,35 @@
NodePointer Demangler::demangleBoundGenericArgs(NodePointer Nominal,
const Vector<NodePointer> &TypeLists,
size_t TypeListIdx) {
- if (!Nominal || Nominal->getNumChildren() < 2)
+ // TODO: This would be a lot easier if we represented bound generic args
+ // flatly in the demangling tree, since that's how they're mangled and also
+ // how the runtime generally wants to consume them.
+
+ if (!Nominal)
return nullptr;
if (TypeListIdx >= TypeLists.size())
return nullptr;
+
+ // Associate a symbolic reference with all remaining generic arguments.
+ if (Nominal->getKind() == Node::Kind::SymbolicReference
+ || Nominal->getKind() == Node::Kind::UnresolvedSymbolicReference) {
+ auto remainingTypeList = createNode(Node::Kind::TypeList);
+ for (unsigned i = TypeLists.size() - 1;
+ i >= TypeListIdx && i < TypeLists.size();
+ --i) {
+ auto list = TypeLists[i];
+ for (auto child : *list) {
+ remainingTypeList->addChild(child, *this);
+ }
+ }
+ return createWithChildren(Node::Kind::BoundGenericOtherNominalType,
+ createType(Nominal), remainingTypeList);
+ }
+
+ if (Nominal->getNumChildren() < 2)
+ return nullptr;
+
NodePointer args = TypeLists[TypeListIdx++];
// Generic arguments for the outermost type come first.
@@ -1286,6 +1313,9 @@
case Node::Kind::Enum:
kind = Node::Kind::BoundGenericEnum;
break;
+ case Node::Kind::OtherNominalType:
+ kind = Node::Kind::BoundGenericOtherNominalType;
+ break;
default:
return nullptr;
}
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index 56a7747..b684122 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -470,6 +470,7 @@
Separator = '_';
break;
+ case Node::Kind::BoundGenericOtherNominalType:
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericClass: {
@@ -1983,11 +1984,13 @@
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericClass:
+ case Node::Kind::BoundGenericOtherNominalType:
return true;
case Node::Kind::Structure:
case Node::Kind::Enum:
case Node::Kind::Class:
+ case Node::Kind::OtherNominalType:
return isSpecialized(node->getChild(0));
case Node::Kind::Extension:
@@ -2002,7 +2005,8 @@
switch (node->getKind()) {
case Node::Kind::Structure:
case Node::Kind::Enum:
- case Node::Kind::Class: {
+ case Node::Kind::Class:
+ case Node::Kind::OtherNominalType: {
NodePointer result = Factory.createNode(node->getKind());
NodePointer parentOrModule = node->getChild(0);
if (isSpecialized(parentOrModule))
@@ -2015,7 +2019,8 @@
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
- case Node::Kind::BoundGenericClass: {
+ case Node::Kind::BoundGenericClass:
+ case Node::Kind::BoundGenericOtherNominalType: {
NodePointer unboundType = node->getChild(0);
assert(unboundType->getKind() == Node::Kind::Type);
NodePointer nominalType = unboundType->getChild(0);
diff --git a/lib/Demangling/TypeDecoder.cpp b/lib/Demangling/TypeDecoder.cpp
index 30714ab..a30f037 100644
--- a/lib/Demangling/TypeDecoder.cpp
+++ b/lib/Demangling/TypeDecoder.cpp
@@ -24,6 +24,7 @@
case Demangle::Node::Kind::BoundGenericClass:
case Demangle::Node::Kind::BoundGenericEnum:
case Demangle::Node::Kind::BoundGenericStructure:
+ case Demangle::Node::Kind::BoundGenericOtherNominalType:
// Bound generic types have a 'Type' node under them, whose child is
// the non-generic reference. If we don't see that structure, do nothing.
if (node->getNumChildren() < 2 ||
@@ -37,7 +38,8 @@
case Demangle::Node::Kind::Class:
case Demangle::Node::Kind::Enum:
- case Demangle::Node::Kind::Structure: {
+ case Demangle::Node::Kind::Structure:
+ case Demangle::Node::Kind::OtherNominalType: {
if (node->getNumChildren() < 2)
return node;
diff --git a/lib/IDE/TypeReconstruction.cpp b/lib/IDE/TypeReconstruction.cpp
index bc79800..a8e779d 100644
--- a/lib/IDE/TypeReconstruction.cpp
+++ b/lib/IDE/TypeReconstruction.cpp
@@ -2105,6 +2105,7 @@
case Demangle::Node::Kind::BoundGenericClass:
case Demangle::Node::Kind::BoundGenericStructure:
case Demangle::Node::Kind::BoundGenericEnum:
+ case Demangle::Node::Kind::BoundGenericOtherNominalType:
VisitNodeBoundGeneric(ast, node, result);
break;
@@ -2115,6 +2116,7 @@
case Demangle::Node::Kind::Structure:
case Demangle::Node::Kind::Class:
case Demangle::Node::Kind::Enum:
+ case Demangle::Node::Kind::OtherNominalType:
case Demangle::Node::Kind::Protocol:
VisitNodeNominal(ast, node, result);
break;
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 8d73f7f..3f29b81 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -554,12 +554,11 @@
void IRGenModule::emitRuntimeRegistration() {
// Duck out early if we have nothing to register.
- if (SwiftProtocols.empty()
- && ProtocolConformances.empty()
- && RuntimeResolvableTypes.empty()
- && (!ObjCInterop || (ObjCProtocols.empty() &&
- ObjCClasses.empty() &&
- ObjCCategoryDecls.empty())))
+ if (SwiftProtocols.empty() && ProtocolConformances.empty() &&
+ RuntimeResolvableTypes.empty() &&
+ (!ObjCInterop || (ObjCProtocols.empty() && ObjCClasses.empty() &&
+ ObjCCategoryDecls.empty())) &&
+ FieldDescriptors.empty())
return;
// Find the entry point.
@@ -721,6 +720,14 @@
RegIGF.Builder.CreateCall(getRegisterTypeMetadataRecordsFn(), {begin, end});
}
+ if (!FieldDescriptors.empty()) {
+ auto *records = emitFieldDescriptors();
+ auto *begin =
+ llvm::ConstantExpr::getBitCast(records, FieldDescriptorPtrPtrTy);
+ auto *size = llvm::ConstantInt::get(SizeTy, FieldDescriptors.size());
+ RegIGF.Builder.CreateCall(getRegisterFieldDescriptorsFn(), {begin, size});
+ }
+
RegIGF.Builder.CreateRetVoid();
}
@@ -1144,9 +1151,30 @@
while (!LazyMetadata.empty() ||
!LazyTypeContextDescriptors.empty() ||
!LazyFunctionDefinitions.empty() ||
- !LazyFieldTypeAccessors.empty() ||
+ !LazyFieldTypes.empty() ||
!LazyWitnessTables.empty()) {
+ while (!LazyFieldTypes.empty()) {
+ auto info = LazyFieldTypes.pop_back_val();
+ auto &IGM = *info.IGM;
+
+ for (auto fieldType : info.fieldTypes) {
+ if (fieldType->hasArchetype())
+ continue;
+
+ // All of the required attributes are going to be preserved
+ // by field reflection metadata in the mangled name, so
+ // there is no need to worry about ownership semantics here.
+ if (auto refStorTy = dyn_cast<ReferenceStorageType>(fieldType))
+ fieldType = refStorTy.getReferentType();
+
+ // Make sure that all of the field type metadata is forced,
+ // otherwise there might be a problem when fields are accessed
+ // through reflection.
+ (void)irgen::getOrCreateTypeMetadataAccessFunction(IGM, fieldType);
+ }
+ }
+
// Emit any lazy type metadata we require.
while (!LazyMetadata.empty()) {
NominalTypeDecl *Nominal = LazyMetadata.pop_back_val();
@@ -1164,11 +1192,6 @@
emitLazyTypeContextDescriptor(*IGM.get(), Nominal);
}
}
- while (!LazyFieldTypeAccessors.empty()) {
- auto accessor = LazyFieldTypeAccessors.pop_back_val();
- emitFieldTypeAccessor(*accessor.IGM, accessor.type, accessor.fn,
- accessor.fieldTypes);
- }
while (!LazyWitnessTables.empty()) {
SILWitnessTable *wt = LazyWitnessTables.pop_back_val();
CurrentIGMPtr IGM = getGenModule(wt->getConformance()->getDeclContext());
@@ -2848,6 +2871,52 @@
return var;
}
+llvm::Constant *IRGenModule::emitFieldDescriptors() {
+ std::string sectionName;
+ switch (TargetInfo.OutputObjectFormat) {
+ case llvm::Triple::MachO:
+ sectionName = "__TEXT, __swift5_fieldmd, regular, no_dead_strip";
+ break;
+ case llvm::Triple::ELF:
+ sectionName = "swift5_fieldmd";
+ break;
+ case llvm::Triple::COFF:
+ sectionName = ".swift5_fieldmd";
+ break;
+ default:
+ llvm_unreachable("Don't know how to emit field records table for "
+ "the selected object format.");
+ }
+
+ // Do nothing if the list is empty.
+ if (FieldDescriptors.empty())
+ return nullptr;
+
+ // Define the global variable for the field record list.
+ // We have to do this before defining the initializer since the entries will
+ // contain offsets relative to themselves.
+ auto arrayTy =
+ llvm::ArrayType::get(FieldDescriptorPtrTy, FieldDescriptors.size());
+
+ // FIXME: This needs to be a linker-local symbol in order for Darwin ld to
+ // resolve relocations relative to it.
+ auto var = new llvm::GlobalVariable(
+ Module, arrayTy,
+ /*isConstant*/ true, llvm::GlobalValue::PrivateLinkage,
+ /*initializer*/ nullptr, "\x01l_type_metadata_table");
+
+ SmallVector<llvm::Constant *, 8> elts;
+ for (auto *descriptor : FieldDescriptors)
+ elts.push_back(
+ llvm::ConstantExpr::getBitCast(descriptor, FieldDescriptorPtrTy));
+
+ var->setInitializer(llvm::ConstantArray::get(arrayTy, elts));
+ var->setSection(sectionName);
+ var->setAlignment(4);
+ addUsedGlobal(var);
+ return var;
+}
+
/// Fetch a global reference to a reference to the given Objective-C class.
/// The result is of type ObjCClassPtrTy->getPointerTo().
Address IRGenModule::getAddrOfObjCClassRef(ClassDecl *theClass) {
diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp
index 59881a5..1f9ba17 100644
--- a/lib/IRGen/GenEnum.cpp
+++ b/lib/IRGen/GenEnum.cpp
@@ -158,21 +158,7 @@
TI->initializeWithTake(IGF, dest, src, T, isOutlined);
}
-llvm::Constant *EnumImplStrategy::emitCaseNames() const {
- // Build the list of case names, payload followed by no-payload.
- llvm::SmallString<64> fieldNames;
- for (auto &payloadCase : getElementsWithPayload()) {
- fieldNames.append(payloadCase.decl->getName().str());
- fieldNames.push_back('\0');
- }
- for (auto &noPayloadCase : getElementsWithNoPayload()) {
- fieldNames.append(noPayloadCase.decl->getName().str());
- fieldNames.push_back('\0');
- }
- // The final null terminator is provided by getAddrOfGlobalString.
- return IGM.getAddrOfGlobalString(fieldNames,
- /*willBeRelativelyAddressed*/ true);
-}
+bool EnumImplStrategy::isReflectable() const { return true; }
unsigned EnumImplStrategy::getPayloadSizeForMetadata() const {
llvm_unreachable("don't need payload size for this enum kind");
@@ -1109,11 +1095,11 @@
llvm_unreachable("no extra inhabitants");
}
- llvm::Constant *emitCaseNames() const override {
+ bool isReflectable() const override {
// C enums have arbitrary values and we don't preserve the mapping
- // between the case and raw value at runtime, so don't emit any
- // case names at all so that reflection can give up in this case.
- return nullptr;
+ // between the case and raw value at runtime, so don't mark it as
+ // reflectable.
+ return false;
}
};
diff --git a/lib/IRGen/GenEnum.h b/lib/IRGen/GenEnum.h
index 262f88e..24dbbd6 100644
--- a/lib/IRGen/GenEnum.h
+++ b/lib/IRGen/GenEnum.h
@@ -224,7 +224,7 @@
}
/// Emit field names for enum reflection.
- virtual llvm::Constant *emitCaseNames() const;
+ virtual bool isReflectable() const;
/// \brief Return the bits used for discriminators for payload cases.
///
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 55511d3..9e8b1e0 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -2709,69 +2709,43 @@
///
/// ABI TODO: This should be unnecessary when the fields that use it are
/// superseded.
- static llvm::Function *
- getFieldTypeAccessorFn(IRGenModule &IGM,
- NominalTypeDecl *type,
- ArrayRef<FieldTypeInfo> fieldTypes) {
- // The accessor function has the following signature:
- // const Metadata * const *(*GetFieldTypes)(const Metadata *T);
- auto metadataArrayPtrTy = IGM.TypeMetadataPtrTy->getPointerTo();
- auto fnTy = llvm::FunctionType::get(metadataArrayPtrTy,
- IGM.TypeMetadataPtrTy,
- /*vararg*/ false);
- auto fn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage,
- llvm::Twine("get_field_types_")
- + type->getName().str(),
- IGM.getModule());
- fn->setAttributes(IGM.constructInitialAttributes());
-
- // Emit the body of the field type accessor later. We need to access
- // the type metadata for the fields, which could lead to infinite recursion
- // in recursive types if we build the field type accessor during metadata
- // generation.
- IGM.addLazyFieldTypeAccessor(type, fieldTypes, fn);
-
- return fn;
+ static void addFieldTypes(IRGenModule &IGM, ArrayRef<CanType> fieldTypes) {
+ IGM.addFieldTypes(fieldTypes);
}
/// Build a field type accessor for stored properties.
///
/// ABI TODO: This should be unnecessary when the fields that use it are
/// superseded.
- static llvm::Function *
- getFieldTypeAccessorFn(IRGenModule &IGM,
- NominalTypeDecl *type,
- NominalTypeDecl::StoredPropertyRange storedProperties){
- SmallVector<FieldTypeInfo, 4> types;
+ static void
+ addFieldTypes(IRGenModule &IGM, NominalTypeDecl *type,
+ NominalTypeDecl::StoredPropertyRange storedProperties) {
+ SmallVector<CanType, 4> types;
for (VarDecl *prop : storedProperties) {
auto propertyType = type->mapTypeIntoContext(prop->getInterfaceType())
->getCanonicalType();
- types.push_back(FieldTypeInfo(propertyType,
- /*indirect*/ false,
- propertyType->is<WeakStorageType>()));
+ types.push_back(propertyType);
}
- return getFieldTypeAccessorFn(IGM, type, types);
+
+ addFieldTypes(IGM, types);
}
/// Build a case type accessor for enum payloads.
///
/// ABI TODO: This should be unnecessary when the fields that use it are
/// superseded.
- static llvm::Function *
- getFieldTypeAccessorFn(IRGenModule &IGM,
- NominalTypeDecl *type,
- ArrayRef<EnumImplStrategy::Element> enumElements) {
- SmallVector<FieldTypeInfo, 4> types;
+ static void addFieldTypes(IRGenModule &IGM,
+ ArrayRef<EnumImplStrategy::Element> enumElements) {
+ SmallVector<CanType, 4> types;
for (auto &elt : enumElements) {
auto caseType = elt.decl->getParentEnum()->mapTypeIntoContext(
elt.decl->getArgumentInterfaceType())
->getCanonicalType();
- bool isIndirect = elt.decl->isIndirect()
- || elt.decl->getParentEnum()->isIndirect();
- types.push_back(FieldTypeInfo(caseType, isIndirect, /*weak*/ false));
+ types.push_back(caseType);
}
- return getFieldTypeAccessorFn(IGM, type, types);
+
+ addFieldTypes(IGM, types);
}
@@ -2805,28 +2779,12 @@
}
void addLayoutInfo() {
- // Build the field name list.
- llvm::SmallString<64> fieldNames;
- unsigned numFields = getFieldNameString(getType()->getStoredProperties(),
- fieldNames);
-
- B.addInt32(numFields);
+ auto properties = getType()->getStoredProperties();
+ B.addInt32(std::distance(properties.begin(), properties.end()));
B.addInt32(FieldVectorOffset / IGM.getPointerSize());
- B.addRelativeAddress(IGM.getAddrOfGlobalString(fieldNames,
- /*willBeRelativelyAddressed*/ true));
-
- // Don't emit the field type accessor function if we're only lazily
- // emitting the context descriptor.
- if (Lazy) {
- B.addInt32(0);
- } else {
- // Build the field type accessor function.
- llvm::Function *fieldTypeVectorAccessor
- = getFieldTypeAccessorFn(IGM, getType(),
- getType()->getStoredProperties());
-
- B.addRelativeAddress(fieldTypeVectorAccessor);
- }
+ B.addInt32(1); // struct always reflectable
+
+ addFieldTypes(IGM, getType(), properties);
}
uint16_t getKindSpecificFlags() {
@@ -2881,21 +2839,9 @@
B.addInt32(numPayloads | (PayloadSizeOffsetInWords << 24));
// # empty cases
B.addInt32(strategy.getElementsWithNoPayload().size());
+ B.addInt32(strategy.isReflectable());
- B.addRelativeAddressOrNull(strategy.emitCaseNames());
-
- // Don't emit the field type accessor function if we're only lazily
- // emitting the context descriptor.
- if (Lazy) {
- B.addInt32(0);
- } else {
- // Build the case type accessor.
- llvm::Function *caseTypeVectorAccessor
- = getFieldTypeAccessorFn(IGM, getType(),
- strategy.getElementsWithPayload());
-
- B.addRelativeAddress(caseTypeVectorAccessor);
- }
+ addFieldTypes(IGM, strategy.getElementsWithPayload());
}
uint16_t getKindSpecificFlags() {
@@ -3029,28 +2975,12 @@
}
void addLayoutInfo() {
- // Build the field name list.
- llvm::SmallString<64> fieldNames;
- unsigned numFields = getFieldNameString(getType()->getStoredProperties(),
- fieldNames);
-
- B.addInt32(numFields);
+ auto properties = getType()->getStoredProperties();
+ B.addInt32(std::distance(properties.begin(), properties.end()));
B.addInt32(FieldVectorOffset / IGM.getPointerSize());
- B.addRelativeAddress(IGM.getAddrOfGlobalString(fieldNames,
- /*willBeRelativelyAddressed*/ true));
-
- // Don't emit the field type accessor function if we're only lazily
- // emitting the context descriptor.
- if (Lazy) {
- B.addInt32(0);
- } else {
- // Build the field type accessor function.
- llvm::Function *fieldTypeVectorAccessor
- = getFieldTypeAccessorFn(IGM, getType(),
- getType()->getStoredProperties());
+ B.addInt32(1); // class is always reflectable
- B.addRelativeAddress(fieldTypeVectorAccessor);
- }
+ addFieldTypes(IGM, getType(), properties);
}
};
} // end anonymous namespace
@@ -3146,158 +3076,8 @@
[&]{ AnonymousContextDescriptorBuilder(*this, DC).emit(); });
}
-void
-IRGenModule::addLazyFieldTypeAccessor(NominalTypeDecl *type,
- ArrayRef<FieldTypeInfo> fieldTypes,
- llvm::Function *fn) {
- IRGen.addLazyFieldTypeAccessor(type, fieldTypes, fn, this);
-}
-
-void
-irgen::emitFieldTypeAccessor(IRGenModule &IGM,
- NominalTypeDecl *type,
- llvm::Function *fn,
- ArrayRef<FieldTypeInfo> fieldTypes)
-{
- IRGenFunction IGF(IGM, fn);
- if (IGM.DebugInfo)
- IGM.DebugInfo->emitArtificialFunction(IGF, fn);
-
- auto metadataArrayPtrTy = IGM.TypeMetadataPtrTy->getPointerTo();
-
- CanType formalType = type->getDeclaredTypeInContext()->getCanonicalType();
- llvm::Value *metadata = IGF.collectParameters().claimNext();
- setTypeMetadataName(IGM, metadata, formalType);
-
- // Get the address at which the field type vector reference should be
- // cached.
- llvm::Value *vectorPtr;
- auto nullVector = llvm::ConstantPointerNull::get(metadataArrayPtrTy);
-
- // If the type is not generic, we can use a global variable to cache the
- // address of the field type vector for the single instance.
- if (!type->isGenericContext()) {
- vectorPtr = new llvm::GlobalVariable(*IGM.getModule(),
- metadataArrayPtrTy,
- /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage,
- nullVector,
- llvm::Twine("field_type_vector_")
- + type->getName().str());
- // For a generic type, use a slot we saved in the generic metadata pattern
- // immediately after the metadata object itself, which should be
- // instantiated with every generic metadata instance.
- } else {
- auto size = IGM.getMetadataLayout(type).getSize();
- auto index = -(size.AddressPoint.getValue() /
- int64_t(IGM.getPointerSize().getValue())) - 1;
- auto offset = IGM.getSize(Size(index));
-
- vectorPtr = IGF.Builder.CreateBitCast(metadata,
- metadataArrayPtrTy->getPointerTo());
- vectorPtr = IGF.Builder.CreateInBoundsGEP(
- /*Ty=*/nullptr, vectorPtr, offset);
- }
-
- // First, see if the field type vector has already been populated. This
- // load can be nonatomic; if we race to build the field offset vector, we
- // will detect so when we try to commit our pointer and simply discard the
- // redundant work.
- llvm::Value *initialVector
- = IGF.Builder.CreateLoad(vectorPtr, IGM.getPointerAlignment());
-
- auto entryBB = IGF.Builder.GetInsertBlock();
- auto buildBB = IGF.createBasicBlock("build_field_types");
- auto raceLostBB = IGF.createBasicBlock("race_lost");
- auto doneBB = IGF.createBasicBlock("done");
-
- llvm::Value *isNull
- = IGF.Builder.CreateICmpEQ(initialVector, nullVector);
- IGF.Builder.CreateCondBr(isNull, buildBB, doneBB);
-
- // Build the field type vector if we didn't already.
- IGF.Builder.emitBlock(buildBB);
-
- // Bind the metadata instance to our local type data so we
- // use it to provide metadata for generic parameters in field types.
- IGF.bindLocalTypeDataFromTypeMetadata(formalType, IsExact, metadata);
-
- // Allocate storage for the field vector.
- unsigned allocSize = fieldTypes.size() * IGM.getPointerSize().getValue();
- auto allocSizeVal = llvm::ConstantInt::get(IGM.IntPtrTy, allocSize);
- auto allocAlignMaskVal =
- IGM.getSize(IGM.getPointerAlignment().asSize() - Size(1));
- llvm::Value *builtVectorAlloc
- = IGF.emitAllocRawCall(allocSizeVal, allocAlignMaskVal);
-
- llvm::Value *builtVector
- = IGF.Builder.CreateBitCast(builtVectorAlloc, metadataArrayPtrTy);
-
- // Emit type metadata for the fields into the vector.
- for (unsigned i : indices(fieldTypes)) {
- auto fieldTy = fieldTypes[i].getType();
- auto slot = IGF.Builder.CreateInBoundsGEP(builtVector,
- llvm::ConstantInt::get(IGM.Int32Ty, i));
-
- // Strip reference storage qualifiers like unowned and weak.
- // FIXME: Some clients probably care about them.
- if (auto refStorTy = dyn_cast<ReferenceStorageType>(fieldTy))
- fieldTy = refStorTy.getReferentType();
-
- auto metadata = IGF.emitTypeMetadataRef(fieldTy);
-
- auto fieldTypeInfo = fieldTypes[i];
-
- // Mix in flag bits.
- if (fieldTypeInfo.hasFlags()) {
- auto flags = FieldType()
- .withIndirect(fieldTypeInfo.isIndirect())
- .withWeak(fieldTypeInfo.isWeak());
- auto metadataBits = IGF.Builder.CreatePtrToInt(metadata, IGF.IGM.SizeTy);
- metadataBits = IGF.Builder.CreateOr(metadataBits,
- llvm::ConstantInt::get(IGF.IGM.SizeTy, flags.getIntValue()));
- metadata = IGF.Builder.CreateIntToPtr(metadataBits, metadata->getType());
- }
-
- IGF.Builder.CreateStore(metadata, slot, IGM.getPointerAlignment());
- }
-
- // Atomically compare-exchange a pointer to our vector into the slot.
- auto vectorIntPtr = IGF.Builder.CreateBitCast(vectorPtr,
- IGM.IntPtrTy->getPointerTo());
- auto builtVectorInt = IGF.Builder.CreatePtrToInt(builtVector,
- IGM.IntPtrTy);
- auto zero = llvm::ConstantInt::get(IGM.IntPtrTy, 0);
-
- llvm::Value *raceVectorInt = IGF.Builder.CreateAtomicCmpXchg(vectorIntPtr,
- zero, builtVectorInt,
- llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::AtomicOrdering::SequentiallyConsistent);
-
- // We might have added internal control flow above.
- buildBB = IGF.Builder.GetInsertBlock();
-
- // The pointer in the slot should still have been null.
- auto didStore = IGF.Builder.CreateExtractValue(raceVectorInt, 1);
- raceVectorInt = IGF.Builder.CreateExtractValue(raceVectorInt, 0);
- IGF.Builder.CreateCondBr(didStore, doneBB, raceLostBB);
-
- // If the cmpxchg failed, someone beat us to landing their field type
- // vector. Deallocate ours and return the winner.
- IGF.Builder.emitBlock(raceLostBB);
- IGF.emitDeallocRawCall(builtVectorAlloc, allocSizeVal, allocAlignMaskVal);
- auto raceVector = IGF.Builder.CreateIntToPtr(raceVectorInt,
- metadataArrayPtrTy);
- IGF.Builder.CreateBr(doneBB);
-
- // Return the result.
- IGF.Builder.emitBlock(doneBB);
- auto phi = IGF.Builder.CreatePHI(metadataArrayPtrTy, 3);
- phi->addIncoming(initialVector, entryBB);
- phi->addIncoming(builtVector, buildBB);
- phi->addIncoming(raceVector, raceLostBB);
-
- IGF.Builder.CreateRet(phi);
+void IRGenModule::addFieldTypes(ArrayRef<CanType> fieldTypes) {
+ IRGen.addFieldTypes(fieldTypes, this);
}
/*****************************************************************************/
diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp
index cd195b6..2b209cc 100644
--- a/lib/IRGen/GenReflection.cpp
+++ b/lib/IRGen/GenReflection.cpp
@@ -963,7 +963,7 @@
}
FieldTypeMetadataBuilder builder(*this, Decl);
- builder.emit();
+ FieldDescriptors.push_back(builder.emit());
}
void IRGenModule::emitReflectionMetadataVersion() {
diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp
index c71c3c3..6090a40 100644
--- a/lib/IRGen/IRGen.cpp
+++ b/lib/IRGen/IRGen.cpp
@@ -767,6 +767,7 @@
// Register our info with the runtime if needed.
if (Opts.UseJIT) {
+ IGM.emitBuiltinReflectionMetadata();
IGM.emitRuntimeRegistration();
} else {
// Emit protocol conformances into a section we can recognize at runtime.
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index 5c97108..1052312 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -323,7 +323,6 @@
Int32Ty,
Int32Ty,
Int32Ty,
- Int32Ty,
Int16Ty,
Int16Ty,
Int32Ty,
@@ -345,6 +344,7 @@
FieldDescriptorTy
= llvm::StructType::create(LLVMContext, "swift.field_descriptor");
FieldDescriptorPtrTy = FieldDescriptorTy->getPointerTo(DefaultAS);
+ FieldDescriptorPtrPtrTy = FieldDescriptorPtrTy->getPointerTo(DefaultAS);
FixedBufferTy = nullptr;
for (unsigned i = 0; i != MaxNumValueWitnesses; ++i)
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 25ee44e..f276a81 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -212,15 +212,13 @@
llvm::SmallPtrSet<SILFunction*, 4> LazilyEmittedFunctions;
- struct LazyFieldTypeAccessor {
- NominalTypeDecl *type;
- std::vector<FieldTypeInfo> fieldTypes;
- llvm::Function *fn;
+ struct FieldTypeMetadata {
IRGenModule *IGM;
+ std::vector<CanType> fieldTypes;
};
-
- /// Field type accessors we need to emit.
- llvm::SmallVector<LazyFieldTypeAccessor, 4> LazyFieldTypeAccessors;
+
+ /// Field types we need to verify are present.
+ llvm::SmallVector<FieldTypeMetadata, 4> LazyFieldTypes;
/// SIL functions that we need to emit lazily.
llvm::SmallVector<SILFunction*, 4> LazyFunctionDefinitions;
@@ -363,13 +361,8 @@
/// Adds \p Conf to LazyWitnessTables if it has not been added yet.
void addLazyWitnessTable(const ProtocolConformance *Conf);
- void addLazyFieldTypeAccessor(NominalTypeDecl *type,
- ArrayRef<FieldTypeInfo> fieldTypes,
- llvm::Function *fn,
- IRGenModule *IGM) {
- LazyFieldTypeAccessors.push_back({type,
- {fieldTypes.begin(), fieldTypes.end()},
- fn, IGM});
+ void addFieldTypes(ArrayRef<CanType> fieldTypes, IRGenModule *IGM) {
+ LazyFieldTypes.push_back({IGM, {fieldTypes.begin(), fieldTypes.end()}});
}
void addClassForEagerInitialization(ClassDecl *ClassDecl);
@@ -545,6 +538,7 @@
llvm::PointerType *TypeMetadataRecordPtrTy;
llvm::StructType *FieldDescriptorTy;
llvm::PointerType *FieldDescriptorPtrTy;
+ llvm::PointerType *FieldDescriptorPtrPtrTy;
llvm::PointerType *ErrorPtrTy; /// %swift.error*
llvm::StructType *OpenedErrorTripleTy; /// { %swift.opaque*, %swift.type*, i8** }
llvm::PointerType *OpenedErrorTriplePtrTy; /// { %swift.opaque*, %swift.type*, i8** }*
@@ -764,14 +758,13 @@
void addUsedGlobal(llvm::GlobalValue *global);
void addCompilerUsedGlobal(llvm::GlobalValue *global);
void addObjCClass(llvm::Constant *addr, bool nonlazy);
+ void addFieldTypes(ArrayRef<CanType> fieldTypes);
+ void addProtocolConformance(const NormalProtocolConformance *conformance);
- void addLazyFieldTypeAccessor(NominalTypeDecl *type,
- ArrayRef<FieldTypeInfo> fieldTypes,
- llvm::Function *fn);
llvm::Constant *emitSwiftProtocols();
llvm::Constant *emitProtocolConformances();
- void addProtocolConformance(const NormalProtocolConformance *conformance);
llvm::Constant *emitTypeMetadataRecords();
+ llvm::Constant *emitFieldDescriptors();
llvm::Constant *getOrCreateHelperFunction(StringRef name,
llvm::Type *resultType,
@@ -886,7 +879,10 @@
/// List of ExtensionDecls corresponding to the generated
/// categories.
SmallVector<ExtensionDecl*, 4> ObjCCategoryDecls;
-
+
+ /// List of fields descriptors to register in runtime.
+ SmallVector<llvm::GlobalVariable *, 4> FieldDescriptors;
+
/// Map of Objective-C protocols and protocol references, bitcast to i8*.
/// The interesting global variables relating to an ObjC protocol.
struct ObjCProtocolPair {
diff --git a/stdlib/public/runtime/ImageInspection.h b/stdlib/public/runtime/ImageInspection.h
index 021bebb..1d64e31 100644
--- a/stdlib/public/runtime/ImageInspection.h
+++ b/stdlib/public/runtime/ImageInspection.h
@@ -44,12 +44,18 @@
/// Load the metadata from the image necessary to find a type by name.
void initializeTypeMetadataRecordLookup();
+/// Load the metadata from the image necessary to find field types
+/// based on the nominal type name.
+void initializeTypeFieldLookup();
+
// Callbacks to register metadata from an image to the runtime.
- void addImageProtocolsBlockCallback(const void *start, uintptr_t size);
+void addImageProtocolsBlockCallback(const void *start, uintptr_t size);
void addImageProtocolConformanceBlockCallback(const void *start,
uintptr_t size);
void addImageTypeMetadataRecordBlockCallback(const void *start,
uintptr_t size);
+void addImageTypeFieldDescriptorBlockCallback(const void *start,
+ uintptr_t size);
int lookupSymbol(const void *address, SymbolInfo *info);
diff --git a/stdlib/public/runtime/ImageInspectionELF.cpp b/stdlib/public/runtime/ImageInspectionELF.cpp
index 00b2346..16064ab 100644
--- a/stdlib/public/runtime/ImageInspectionELF.cpp
+++ b/stdlib/public/runtime/ImageInspectionELF.cpp
@@ -86,6 +86,20 @@
}
}
+void swift::initializeTypeFieldLookup() {
+ const swift::MetadataSections *sections = registered;
+ while (true) {
+ const swift::MetadataSections::Range &fields = sections->swift5_fieldmd;
+ if (fields.length)
+ addImageTypeFieldDescriptorBlockCallback(
+ reinterpret_cast<void *>(fields.start), fields.length);
+
+ if (sections->next == registered)
+ break;
+ sections = sections->next;
+ }
+}
+
// As ELF images are loaded, ImageInspectionInit:sectionDataInit() will call
// addNewDSOImage() with an address in the image that can later be used via
// dladdr() to dlopen() the image after the appropriate initialize*Lookup()
diff --git a/stdlib/public/runtime/ImageInspectionMachO.cpp b/stdlib/public/runtime/ImageInspectionMachO.cpp
index 6d490f0..c7d556c 100644
--- a/stdlib/public/runtime/ImageInspectionMachO.cpp
+++ b/stdlib/public/runtime/ImageInspectionMachO.cpp
@@ -38,6 +38,9 @@
/// The Mach-O section name for the section containing type references.
/// This lives within SEG_TEXT.
constexpr const char TypeMetadataRecordSection[] = "__swift5_types";
+/// The Mach-O section name for the section containing type field references.
+/// This lives within SEG_TEXT.
+constexpr const char TypeFieldRecordSection[] = "__swift5_fieldmd";
template<const char *SECTION_NAME,
void CONSUME_BLOCK(const void *start, uintptr_t size)>
@@ -82,6 +85,12 @@
}
+void swift::initializeTypeFieldLookup() {
+ _dyld_register_func_for_add_image(
+ addImageCallback<TypeFieldRecordSection,
+ addImageTypeFieldDescriptorBlockCallback>);
+}
+
int swift::lookupSymbol(const void *address, SymbolInfo *info) {
Dl_info dlinfo;
if (dladdr(address, &dlinfo) == 0) {
diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp
index 45a37ae..91359bc 100644
--- a/stdlib/public/runtime/MetadataLookup.cpp
+++ b/stdlib/public/runtime/MetadataLookup.cpp
@@ -18,6 +18,7 @@
#include "swift/Basic/Lazy.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Demangling/TypeDecoder.h"
+#include "swift/Reflection/Records.h"
#include "swift/Runtime/Casting.h"
#include "swift/Runtime/Concurrent.h"
#include "swift/Runtime/HeapObject.h"
@@ -33,9 +34,11 @@
#include "ImageInspection.h"
#include <functional>
#include <vector>
+#include <list>
using namespace swift;
using namespace Demangle;
+using namespace reflection;
#if SWIFT_OBJC_INTEROP
#include <objc/runtime.h>
@@ -43,6 +46,45 @@
#include <objc/objc.h>
#endif
+/// Produce a Demangler value suitable for resolving runtime type metadata
+/// strings.
+static Demangler getDemanglerForRuntimeTypeResolution() {
+ Demangler dem;
+ // Resolve symbolic references to type contexts into the absolute address of
+ // the type context descriptor, so that if we see a symbolic reference in the
+ // mangled name we can immediately find the associated metadata.
+ dem.setSymbolicReferenceResolver([&](int32_t offset,
+ const void *base) -> NodePointer {
+ auto absolute_addr = (uintptr_t)detail::applyRelativeOffset(base, offset);
+ auto reference = dem.createNode(Node::Kind::SymbolicReference, absolute_addr);
+ auto type = dem.createNode(Node::Kind::Type);
+ type->addChild(reference, dem);
+ return type;
+ });
+ return dem;
+}
+
+template <typename T> struct DescriptorCacheEntry {
+private:
+ std::string Name;
+ const T *Description;
+
+public:
+ DescriptorCacheEntry(const llvm::StringRef name, const T *description)
+ : Name(name.str()), Description(description) {}
+
+ const T *getDescription() { return Description; }
+
+ int compareWithKey(llvm::StringRef aName) const {
+ return aName.compare(Name);
+ }
+
+ template <class... Args>
+ static size_t getExtraAllocationSize(Args &&... ignored) {
+ return 0;
+ }
+};
+
#pragma mark Nominal type descriptor cache
// Type Metadata Cache.
@@ -136,8 +178,16 @@
Demangle::NodePointer node) {
if (node->getKind() == Demangle::Node::Kind::Type)
node = node->getChild(0);
-
+
while (context) {
+ // We can directly match symbolic references to the current context.
+ if (node && node->getKind() == Demangle::Node::Kind::SymbolicReference) {
+ if (equalContexts(context, reinterpret_cast<const ContextDescriptor *>(
+ node->getIndex()))) {
+ return true;
+ }
+ }
+
switch (context->getKind()) {
case ContextDescriptorKind::Module: {
auto module = cast<ModuleContextDescriptor>(context);
@@ -181,10 +231,16 @@
if (!(flags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef))
return false;
break;
+
default:
return false;
}
- if (!node->getChild(1)->getText().equals(type->Name.get()))
+
+ auto nameNode = node->getChild(1);
+ if (nameNode->getKind() == Demangle::Node::Kind::PrivateDeclName)
+ return false;
+
+ if (nameNode->getText() != type->Name.get())
return false;
node = node->getChild(0);
@@ -233,9 +289,12 @@
auto &T = TypeMetadataRecords.get();
// If we have a symbolic reference to a context, resolve it immediately.
- if (node->getKind() == Node::Kind::SymbolicReference)
+ NodePointer symbolicNode = node;
+ if (symbolicNode->getKind() == Node::Kind::Type)
+ symbolicNode = symbolicNode->getChild(0);
+ if (symbolicNode->getKind() == Node::Kind::SymbolicReference)
return cast<TypeContextDescriptor>(
- (const ContextDescriptor *)node->getIndex());
+ (const ContextDescriptor *)symbolicNode->getIndex());
auto mangledName = Demangle::mangleNode(node);
@@ -274,32 +333,8 @@
}
};
- struct ProtocolDescriptorCacheEntry {
- private:
- std::string Name;
- const ProtocolDescriptor *Description;
-
- public:
- ProtocolDescriptorCacheEntry(const llvm::StringRef name,
- const ProtocolDescriptor *description)
- : Name(name.str()), Description(description) {}
-
- const ProtocolDescriptor *getDescription() {
- return Description;
- }
-
- int compareWithKey(llvm::StringRef aName) const {
- return aName.compare(Name);
- }
-
- template <class... T>
- static size_t getExtraAllocationSize(T &&... ignored) {
- return 0;
- }
- };
-
struct ProtocolMetadataState {
- ConcurrentMap<ProtocolDescriptorCacheEntry> ProtocolCache;
+ ConcurrentMap<DescriptorCacheEntry<ProtocolDescriptor>> ProtocolCache;
std::vector<ProtocolSection> SectionsToScan;
Mutex SectionsToScanLock;
@@ -388,6 +423,94 @@
return foundProtocol;
}
+#pragma mark Type field descriptor cache
+namespace {
+template <typename T> struct FieldDescriptorCacheEntry {
+private:
+ const Metadata *Base;
+ const T *Description;
+
+public:
+ FieldDescriptorCacheEntry(const Metadata *Base, const T *description)
+ : Base(Base), Description(description) {}
+
+ const T *getDescription() { return Description; }
+
+ int compareWithKey(const Metadata *other) const {
+ return Base == other;
+ }
+
+ template <class... Args>
+ static size_t getExtraAllocationSize(Args &&... ignored) {
+ return 0;
+ }
+};
+
+class StaticFieldSection {
+ const void *Begin;
+ const void *End;
+
+public:
+ StaticFieldSection(const void *begin, const void *end)
+ : Begin(begin), End(end) {}
+
+ FieldDescriptorIterator begin() const {
+ return FieldDescriptorIterator(Begin, End);
+ }
+
+ FieldDescriptorIterator end() const {
+ return FieldDescriptorIterator(End, End);
+ }
+};
+
+class DynamicFieldSection {
+ const FieldDescriptor **Begin;
+ const FieldDescriptor **End;
+
+public:
+ DynamicFieldSection(const FieldDescriptor **fields, size_t size)
+ : Begin(fields), End(fields + size) {}
+
+ const FieldDescriptor **begin() { return Begin; }
+
+ const FieldDescriptor **end() const { return End; }
+};
+
+struct FieldCacheState {
+ ConcurrentMap<FieldDescriptorCacheEntry<FieldDescriptor>> FieldCache;
+
+ Mutex SectionsLock;
+ std::vector<StaticFieldSection> StaticSections;
+ std::vector<DynamicFieldSection> DynamicSections;
+
+ FieldCacheState() {
+ StaticSections.reserve(16);
+ DynamicSections.reserve(8);
+ initializeTypeFieldLookup();
+ }
+};
+
+static Lazy<FieldCacheState> FieldCache;
+} // namespace
+
+void swift::swift_registerFieldDescriptors(const FieldDescriptor **records,
+ size_t size) {
+ auto &cache = FieldCache.get();
+ ScopedLock guard(cache.SectionsLock);
+ cache.DynamicSections.push_back({records, size});
+}
+
+void swift::addImageTypeFieldDescriptorBlockCallback(const void *recordsBegin,
+ uintptr_t size) {
+ auto sectionBytes = reinterpret_cast<const char *>(recordsBegin);
+ auto recordsEnd = reinterpret_cast<const void *>(sectionBytes + size);
+
+ // Field cache should always be sufficiently initialized by this point.
+ auto &cache = FieldCache.unsafeGetAlreadyInitialized();
+ ScopedLock guard(cache.SectionsLock);
+ cache.StaticSections.push_back({recordsBegin, recordsEnd});
+}
+
#pragma mark Metadata lookup via mangled name
#if SWIFT_OBJC_INTEROP
@@ -841,7 +964,7 @@
TypeInfo
swift::_getTypeByMangledName(StringRef typeName,
SubstGenericParameterFn substGenericParam) {
- Demangler demangler;
+ auto demangler = getDemanglerForRuntimeTypeResolution();
NodePointer node;
// Check whether this is the convenience syntax "ModuleName.ClassName".
@@ -856,16 +979,6 @@
return dotPos;
};
- // Resolve symbolic references to type contexts into the absolute address of
- // the type context descriptor, so that if we see a symbolic reference in the
- // mangled name we can immediately find the associated metadata.
- demangler.setSymbolicReferenceResolver(
- [&](int32_t offset, const void *base) -> NodePointer {
- auto absolute_addr = (uintptr_t)detail::applyRelativeOffset(base, offset);
- return demangler.createNode(Node::Kind::SymbolicReference,
- absolute_addr);
- });
-
auto dotPos = getDotPosForConvenienceSyntax();
if (dotPos != llvm::StringRef::npos) {
// Form a demangle tree for this class.
@@ -873,7 +986,7 @@
NodePointer moduleNode = demangler.createNode(Node::Kind::Module,
typeName.substr(0, dotPos));
NodePointer nameNode = demangler.createNode(Node::Kind::Identifier,
- typeName.substr(dotPos + 1));
+ typeName.substr(dotPos + 1));
classNode->addChild(moduleNode, demangler);
classNode->addChild(nameNode, demangler);
@@ -929,3 +1042,106 @@
return flatSubstitutions[flatIndex];
});
}
+
+void swift::swift_getFieldAt(
+ const Metadata *base, unsigned index,
+ std::function<void(llvm::StringRef name, FieldType fieldInfo)>
+ callback) {
+ auto *baseDesc = base->getTypeContextDescriptor();
+ if (!baseDesc)
+ return;
+
+ auto getFieldAt = [&](const FieldDescriptor &descriptor) {
+ auto &field = descriptor.getFields()[index];
+ auto name = field.getFieldName(0);
+
+ // Enum cases don't always have types.
+ if (!field.hasMangledTypeName()) {
+ callback(name, FieldType().withIndirect(field.isIndirectCase()));
+ return;
+ }
+
+ std::vector<const ContextDescriptor *> descriptorPath;
+ {
+ const auto *parent = reinterpret_cast<
+ const ContextDescriptor *>(baseDesc);
+ while (parent) {
+ if (parent->isGeneric())
+ descriptorPath.push_back(parent);
+
+ parent = parent->Parent.get();
+ }
+ }
+
+ auto typeInfo = _getTypeByMangledName(
+ field.getMangledTypeName(0),
+ [&](unsigned depth, unsigned index) -> const Metadata * {
+ if (depth >= descriptorPath.size())
+ return nullptr;
+
+ unsigned currentDepth = 0;
+ unsigned flatIndex = index;
+ const ContextDescriptor *currentContext = descriptorPath.back();
+
+ for (const auto *context : llvm::reverse(descriptorPath)) {
+ if (currentDepth >= depth)
+ break;
+
+ flatIndex += context->getNumGenericParams();
+ currentContext = context;
+ ++currentDepth;
+ }
+
+ if (index >= currentContext->getNumGenericParams())
+ return nullptr;
+
+ return base->getGenericArgs()[flatIndex];
+ });
+
+ callback(name, FieldType()
+ .withType(typeInfo)
+ .withIndirect(field.isIndirectCase())
+ .withWeak(typeInfo.isWeak()));
+
+ };
+
+ auto dem = getDemanglerForRuntimeTypeResolution();
+ auto &cache = FieldCache.get();
+ auto isRequestedDescriptor = [&](const FieldDescriptor &descriptor) {
+ assert(descriptor.hasMangledTypeName());
+ auto mangledName = descriptor.getMangledTypeName(0);
+
+ if (!_contextDescriptorMatchesMangling(baseDesc,
+ dem.demangleType(mangledName)))
+ return false;
+
+ cache.FieldCache.getOrInsert(base, &descriptor);
+ getFieldAt(descriptor);
+ return true;
+ };
+
+
+ // Fast path: If we already have field descriptor cached.
+ /*
+ if (auto Value = cache.FieldCache.find(base)) {
+ getFieldAt(*Value->getDescription());
+ return;
+ }
+ */
+
+ ScopedLock guard(cache.SectionsLock);
+ // Otherwise let's try to find it in one of the sections.
+ for (auto §ion : cache.DynamicSections) {
+ for (const auto *descriptor : section) {
+ if (isRequestedDescriptor(*descriptor))
+ return;
+ }
+ }
+
+ for (const auto §ion : cache.StaticSections) {
+ for (auto &descriptor : section) {
+ if (isRequestedDescriptor(descriptor))
+ return;
+ }
+ }
+}
diff --git a/stdlib/public/runtime/Reflection.mm b/stdlib/public/runtime/Reflection.mm
index b367017..2d248fe 100644
--- a/stdlib/public/runtime/Reflection.mm
+++ b/stdlib/public/runtime/Reflection.mm
@@ -446,19 +446,6 @@
new (outMirror) Mirror(reflect(owner, eltData, elt.Type));
}
-// Get a field name from a doubly-null-terminated list.
-static const char *getFieldName(const char *fieldNames, size_t i) {
- const char *fieldName = fieldNames;
- for (size_t j = 0; j < i; ++j) {
- size_t len = strlen(fieldName);
- assert(len != 0);
- fieldName += len + 1;
- }
-
- return fieldName;
-}
-
-
static bool loadSpecialReferenceStorage(HeapObject *owner,
OpaqueValue *fieldData,
const FieldType fieldType,
@@ -552,25 +539,26 @@
if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
- // Load the type and offset from their respective vectors.
- auto fieldType = Struct->getFieldTypes()[i];
+ // Load the offset from its vector.
auto fieldOffset = Struct->getFieldOffsets()[i];
- auto bytes = reinterpret_cast<char*>(value);
- auto fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
+ swift_getFieldAt(type, i, [&](llvm::StringRef name, FieldType fieldInfo) {
+ new (outString) String(name.data(), name.size());
- new (outString) String(getFieldName(Struct->getDescription()->FieldNames, i));
+ // 'owner' is consumed by this call.
+ SWIFT_CC_PLUSZERO_GUARD(swift_unknownRetain(owner));
- // 'owner' is consumed by this call.
- SWIFT_CC_PLUSZERO_GUARD(swift_unknownRetain(owner));
+ assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
- assert(!fieldType.isIndirect() && "indirect struct fields not implemented");
+ auto bytes = reinterpret_cast<char *>(value);
+ auto fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
- // This only consumed owner if we succeed.
- if (loadSpecialReferenceStorage(owner, fieldData, fieldType, outMirror))
- return;
+ // This only consumed owner if we succeed.
+ if (loadSpecialReferenceStorage(owner, fieldData, fieldInfo, outMirror))
+ return;
- new (outMirror) Mirror(reflect(owner, fieldData, fieldType.getType()));
+ new (outMirror) Mirror(reflect(owner, fieldData, fieldInfo.getType()));
+ });
}
// -- Enum destructuring.
@@ -580,17 +568,14 @@
const auto &Description = *Enum->getDescription();
// No metadata for C and @objc enums yet
- if (Description.CaseNames == nullptr)
- return false;
-
- return true;
+ return Description.IsReflectable;
}
-static void getEnumMirrorInfo(const OpaqueValue *value,
- const Metadata *type,
- unsigned *tagPtr,
- const Metadata **payloadTypePtr,
- bool *indirectPtr) {
+static const char *getEnumMirrorInfo(const OpaqueValue *value,
+ const Metadata *type,
+ unsigned *tagPtr = nullptr,
+ const Metadata **payloadTypePtr = nullptr,
+ bool *indirectPtr = nullptr) {
const auto Enum = static_cast<const EnumMetadata *>(type);
const auto &Description = *Enum->getDescription();
@@ -605,11 +590,12 @@
const Metadata *payloadType = nullptr;
bool indirect = false;
- if (static_cast<unsigned>(tag) < payloadCases) {
- auto payload = Description.GetCaseTypes(type)[tag];
- payloadType = payload.getType();
- indirect = payload.isIndirect();
- }
+ const char *caseName = nullptr;
+ swift_getFieldAt(type, tag, [&](llvm::StringRef name, FieldType info) {
+ caseName = name.data();
+ payloadType = info.getType();
+ indirect = info.isIndirect();
+ });
if (tagPtr)
*tagPtr = tag;
@@ -617,6 +603,8 @@
*payloadTypePtr = payloadType;
if (indirectPtr)
*indirectPtr = indirect;
+
+ return caseName;
}
// internal func _swift_EnumMirror_caseName(
@@ -632,15 +620,11 @@
return nullptr;
}
- const auto Enum = static_cast<const EnumMetadata *>(type);
- const auto &Description = *Enum->getDescription();
-
- unsigned tag;
- getEnumMirrorInfo(value, type, &tag, nullptr, nullptr);
+ auto caseName = getEnumMirrorInfo(value, type);
SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
- return getFieldName(Description.CaseNames, tag);
+ return caseName;
}
// internal func _getEnumCaseName<T>(_ value: T) -> UnsafePointer<CChar>?
@@ -685,7 +669,7 @@
}
const Metadata *payloadType;
- getEnumMirrorInfo(value, type, nullptr, &payloadType, nullptr);
+ (void)getEnumMirrorInfo(value, type, nullptr, &payloadType, nullptr);
SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
return (payloadType != nullptr) ? 1 : 0;
}
@@ -707,7 +691,7 @@
const Metadata *payloadType;
bool indirect;
- getEnumMirrorInfo(value, type, &tag, &payloadType, &indirect);
+ auto caseName = getEnumMirrorInfo(value, type, &tag, &payloadType, &indirect);
// Copy the enum payload into a box
const Metadata *boxType = (indirect ? &METADATA_SYM(Bo).base : payloadType);
@@ -731,7 +715,7 @@
swift_release(pair.object);
}
- new (outString) String(getFieldName(Description.CaseNames, tag));
+ new (outString) String(caseName);
new (outMirror) Mirror(reflect(owner, value, payloadType));
}
@@ -791,11 +775,6 @@
if (i < 0 || (size_t)i > Clas->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
- // Load the type and offset from their respective vectors.
- auto fieldType = Clas->getFieldTypes()[i];
- assert(!fieldType.isIndirect()
- && "class indirect properties not implemented");
-
// FIXME: If the class has ObjC heritage, get the field offset using the ObjC
// metadata, because we don't update the field offsets in the face of
// resilient base classes.
@@ -812,16 +791,21 @@
#endif
}
- auto bytes = *reinterpret_cast<char * const *>(value);
- auto fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
+ swift_getFieldAt(type, i, [&](llvm::StringRef name, FieldType fieldInfo) {
+ assert(!fieldInfo.isIndirect() &&
+ "class indirect properties not implemented");
- new (outString) String(getFieldName(Clas->getDescription()->FieldNames, i));
+ auto bytes = *reinterpret_cast<char *const *>(value);
+ auto fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
- if (loadSpecialReferenceStorage(owner, fieldData, fieldType, outMirror))
- return;
+ new (outString) String(name.data(), name.size());
- // 'owner' is consumed by this call.
- new (outMirror) Mirror(reflect(owner, fieldData, fieldType.getType()));
+ if (loadSpecialReferenceStorage(owner, fieldData, fieldInfo, outMirror))
+ return;
+
+ // 'owner' is consumed by this call.
+ new (outMirror) Mirror(reflect(owner, fieldData, fieldInfo.getType()));
+ });
}
// -- Mirror witnesses for ObjC classes.
diff --git a/test/IRGen/cf.sil b/test/IRGen/cf.sil
index d52805c..f9cd361 100644
--- a/test/IRGen/cf.sil
+++ b/test/IRGen/cf.sil
@@ -30,7 +30,6 @@
// -- is imported C typedef, is class, is nonunique
// CHECK-64-SAME: <i32 0x1000_0010>
// CHECK-64-SAME: [[MUTABLE_REFRIGERATOR_NAME]]
-// CHECK-64-SAME: @get_field_types_CCMutableRefrigerator
// CHECK-64: @"$SSo24CCMutableRefrigeratorRefaN" = linkonce_odr hidden global <{ {{.*}} }> <{
// CHECK-64-SAME: @initialize_metadata_CCMutableRefrigerator
diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift
index 1e0453f..a274a5b 100644
--- a/test/IRGen/class_resilience.swift
+++ b/test/IRGen/class_resilience.swift
@@ -27,7 +27,6 @@
// CHECK: @"$S16class_resilience30ClassWithIndirectResilientEnumC5colors5Int32VvpWvd" = hidden constant [[INT]] {{12|24}}
// CHECK: [[RESILIENTCHILD_NAME:@.*]] = private constant [15 x i8] c"ResilientChild\00"
-// CHECK: [[RESILIENTCHILD_FIELDS:@.*]] = private constant [7 x i8] c"field\00\00"
// CHECK: @"$S16class_resilience14ResilientChildCMn" = {{(protected )?}}constant <{{.*}}> <{
// -- flags: class, unique, has vtable, has resilient superclass
@@ -38,8 +37,6 @@
// CHECK-SAME: i32 1,
// -- field offset vector offset
// CHECK-SAME: i32 3,
-// -- field names,
-// CHECK-SAME: [7 x i8]* [[RESILIENTCHILD_FIELDS]]
// CHECK-SAME: }>
// CHECK: @"$S16class_resilience14ResilientChildCMo" = {{(protected )?}}global [[INT]] 0
diff --git a/test/IRGen/dllimport.swift b/test/IRGen/dllimport.swift
index ee44b05..c24285c 100644
--- a/test/IRGen/dllimport.swift
+++ b/test/IRGen/dllimport.swift
@@ -40,8 +40,6 @@
// CHECK-NO-OPT-DAG: declare dllimport void @swift_deallocObject(%swift.refcounted*, i32, i32)
// CHECK-NO-OPT-DAG: declare dllimport void @swift_release(%swift.refcounted*)
// CHECK-NO-OPT-DAG: declare dllimport %swift.refcounted* @swift_retain(%swift.refcounted* returned)
-// CHECK-NO-OPT-DAG: declare dllimport i8* @swift_slowAlloc(i32, i32) #2
-// CHECK-NO-OPT-DAG: declare dllimport void @swift_slowDealloc(i8*, i32, i32) #2
// CHECK-NO-OPT-DAG: @"$S9dllexport1cCN" = external dllimport global %swift.type
// CHECK-NO-OPT-DAG: @"$S9dllexport1pMp" = external dllimport global %swift.protocol
// CHECK-NO-OPT-DAG: @"$SytN" = external dllimport global %swift.full_type
@@ -55,8 +53,6 @@
// CHECK-OPT-DAG: @"$SBoWV" = external dllimport global i8*
// CHECK-OPT-DAG: @"$S9dllexport1cCN" = external dllimport global %swift.type
// CHECK-OPT-DAG: @"$S9dllexport1pMp" = external dllimport global %swift.protocol
-// CHECK-OPT-DAG: declare dllimport i8* @swift_slowAlloc(i32, i32) local_unnamed_addr
-// CHECK-OPT-DAG: declare dllimport void @swift_slowDealloc(i8*, i32, i32) local_unnamed_addr
// CHECK-OPT-DAG: declare dllimport swiftcc i8* @"$S9dllexport2ciAA1cCvau"()
// CHECK-OPT-DAG: declare dllimport %swift.type* @"$S9dllexport1cCMa"()
// CHECK-OPT-DAG: declare dllimport void @swift_deallocClassInstance(%swift.refcounted*, i32, i32)
diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil
index bfbda2b..42b7aed 100644
--- a/test/IRGen/enum.sil
+++ b/test/IRGen/enum.sil
@@ -104,7 +104,6 @@
// The witness table pattern includes extra inhabitant witness
// implementations which are used if the instance has extra inhabitants.
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
-// CHECK: [[DYNAMICSINGLETON_FIELD_NAMES:@.*]] = private constant [7 x i8] c"value\00\00"
// CHECK: @"$S4enum16DynamicSingletonOWV" =
// CHECK-SAME: i8* null
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$S4enum16DynamicSingletonOwxs" to i8*)
@@ -117,11 +116,7 @@
// CHECK-SAME: i32 1,
// -- No empty cases
// CHECK-SAME: i32 0,
-// -- Case names
-// CHECK-SAME: [[DYNAMICSINGLETON_FIELD_NAMES]]
// -- Case type accessor
-// CHECK-SAME: @get_field_types_DynamicSingleton
-// -- generic argument offset
// CHECK-SAME: i32 2,
// -- generic parameters, requirements, key, extra
// CHECK-SAME: i32 1, i32 0, i32 1, i32 0
diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil
index ff2167e..d98da2e 100644
--- a/test/IRGen/enum_value_semantics.sil
+++ b/test/IRGen/enum_value_semantics.sil
@@ -162,8 +162,6 @@
// CHECK: i64 2,
// CHECK: {{.*}}* @"$S20enum_value_semantics18GenericFixedLayoutOMn"
// CHECK: i{{32|64}} 0
-// CHECK: %swift.type* null,
-// CHECK: %swift.type** null
// CHECK: }>
sil @single_payload_nontrivial_copy_destroy : $(@owned SinglePayloadNontrivial) -> () {
diff --git a/test/IRGen/field_type_vectors.sil b/test/IRGen/field_type_vectors.sil
index 90d2f77..d4b1129 100644
--- a/test/IRGen/field_type_vectors.sil
+++ b/test/IRGen/field_type_vectors.sil
@@ -5,13 +5,11 @@
import Swift
// CHECK-LABEL: @"$S18field_type_vectors3FooVMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[FOO_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
struct Foo {
var x: Int
}
// CHECK-LABEL: @"$S18field_type_vectors3BarVMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[BAR_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
// CHECK-LABEL: @"$S18field_type_vectors3BarVMP" = internal global
// -- There should be 1 word between the field type vector slot, with type %swift.type**,
// and the address point
@@ -21,7 +19,6 @@
}
// CHECK-LABEL: @"$S18field_type_vectors3BasVMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[BAS_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
// CHECK-LABEL: @"$S18field_type_vectors3BasVMP" = internal global
// -- There should be 1 word between the field type vector slot, with type %swift.type**,
// and the address point
@@ -32,7 +29,6 @@
}
// CHECK-LABEL: @"$S18field_type_vectors3ZimCMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[ZIM_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
// CHECK-LABEL: @"$S18field_type_vectors3ZimCMP" = internal global
// -- There should be 1 word between the field type vector slot, with type %swift.type**,
// and the address point
@@ -47,7 +43,6 @@
sil @_TFC18field_type_vectors3ZimcU___fMGS0_Q_Q0__FT_GS0_Q_Q0__ : $@convention(method) <T, U> (@owned Zim<T, U>) -> @owned Zim<T, U>
// CHECK-LABEL: @"$S18field_type_vectors4ZangCMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[ZANG_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
// CHECK-LABEL: @"$S18field_type_vectors4ZangCMP" = internal global
// -- There should be 1 word between the field type vector slot, with type %swift.type**,
// and the address point
@@ -70,41 +65,3 @@
}
}
sil_vtable StorageQualified {}
-
-// CHECK: [[FOO_TYPE_VECTOR_SLOT:@.*Foo.*]] = private global %swift.type** null
-
-// CHECK: define{{( protected)?}} private %swift.type** [[FOO_TYPES_ACCESSOR]](%swift.type* %Foo)
-// CHECK: [[EXISTING:%.*]] = load %swift.type**, %swift.type*** [[FOO_TYPE_VECTOR_SLOT]]
-// CHECK: [[IS_NULL:%.*]] = icmp eq %swift.type** [[EXISTING]], null
-// CHECK: br i1 [[IS_NULL]], label %[[BUILD_FIELD_TYPES:.*]], label %[[DONE:.*]]
-// CHECK: [[BUILD_FIELD_TYPES]]:
-// CHECK: store {{.*}} @"$SSiN"
-// CHECK: cmpxchg {{.*}} [[FOO_TYPE_VECTOR_SLOT]]
-
-// CHECK: define{{( protected)?}} private %swift.type** [[BAR_TYPES_ACCESSOR]](%swift.type* %"Bar<T>")
-// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Bar<T>" to %swift.type***
-// CHECK: [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i64 -2
-// CHECK: load %swift.type**, %swift.type*** [[SLOT]], align 8
-// CHECK: br
-// CHECK-NOT: load %swift.type*,
-// CHECK: store {{.*}} @"$SSiN"
-
-
-// CHECK: define{{( protected)?}} private %swift.type** [[BAS_TYPES_ACCESSOR]](%swift.type* %"Bas<T, U>")
-// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Bas<T, U>" to %swift.type***
-// CHECK: [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i64 -2
-// CHECK: load %swift.type**, %swift.type*** [[SLOT]], align 8
-// CHECK: br
-// CHECK: store {{.*}} @"$S18field_type_vectors3FooVMf"
-// CHECK: call %swift.type* @"$S18field_type_vectors3BarVMa"(%swift.type* %T)
-
-// CHECK: define{{( protected)?}} private %swift.type** [[ZIM_TYPES_ACCESSOR]](%swift.type* %"Zim<T, U>")
-// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Zim<T, U>" to %swift.type***
-// CHECK: [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i64 -3
-// CHECK: load %swift.type**, %swift.type*** [[SLOT]], align 8
-
-// CHECK: define{{( protected)?}} private %swift.type** [[ZANG_TYPES_ACCESSOR]](%swift.type* %"Zang<V>")
-// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Zang<V>" to %swift.type***
-// CHECK: [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i64 -3
-// CHECK: load %swift.type**, %swift.type*** [[SLOT]], align 8
-
diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil
index 1dde5f5..3f0c58d 100644
--- a/test/IRGen/generic_classes.sil
+++ b/test/IRGen/generic_classes.sil
@@ -13,7 +13,6 @@
// -- offset of RootGeneric<T>.x
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[ROOTGENERIC_NAME:@.*]] = private constant [12 x i8] c"RootGeneric\00"
-// CHECK: [[ROOTGENERIC_FIELDS:@.*]] = private constant [7 x i8] c"x\00y\00z\00\00"
// CHECK-LABEL: @"$S15generic_classes11RootGenericCMn" =
// -- flags: class, generic, unique, has vtable
@@ -24,8 +23,6 @@
// CHECK-SAME: i32 3,
// -- field offset vector offset
// CHECK-SAME: i32 15,
-// -- field names
-// CHECK-SAME: [7 x i8]* [[ROOTGENERIC_FIELDS]]
// -- generic parameter vector offset
// CHECK-SAME: i32 10,
// -- generic parameters, requirements, key arguments, extra arguments
@@ -63,8 +60,6 @@
// CHECK-SAME: i32 3,
// -- -- field offset vector offset
// CHECK-SAME: i32 11,
-// -- field names
-// CHECK-SAME: [7 x i8]* [[ROOTGENERIC_FIELDS]]
// CHECK-SAME: }>
// CHECK: @"$S15generic_classes14RootNonGenericCMf" = internal global <{ {{.*}} }> <{
diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil
index c8d4fea..cadee5d 100644
--- a/test/IRGen/generic_structs.sil
+++ b/test/IRGen/generic_structs.sil
@@ -20,7 +20,6 @@
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [14 x i8] c"SingleDynamic\00"
-// CHECK: [[SINGLEDYNAMIC_FIELDS:@.*]] = private constant [3 x i8] c"x\00\00"
// CHECK: @"$S15generic_structs13SingleDynamicVMn" = hidden constant
// -- flags: struct, unique, generic
// CHECK-SAME: <i32 0x0000_00D1>
@@ -30,8 +29,6 @@
// CHECK-SAME: i32 1,
// -- field offset vector offset
// CHECK-SAME: i32 3,
-// -- field names
-// CHECK-SAME: [3 x i8]* [[SINGLEDYNAMIC_FIELDS]]
// -- generic parameter vector offset
// CHECK-SAME: i32 2,
// -- generic params, requirements, key args, extra args
@@ -53,7 +50,6 @@
// -- Nominal type descriptor for generic struct with protocol requirements
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[DYNAMICWITHREQUIREMENTS_NAME:@.*]] = private constant [24 x i8] c"DynamicWithRequirements\00"
-// CHECK: [[DYNAMICWITHREQUIREMENTS_FIELDS:@.*]] = private constant [5 x i8] c"x\00y\00\00"
// CHECK: @"$S15generic_structs23DynamicWithRequirementsVMn" = hidden constant <{ {{.*}} i32 }> <{
// -- flags: struct, unique, generic
// CHECK-SAME: <i32 0x0000_00D1>
@@ -63,8 +59,6 @@
// CHECK-SAME: i32 2,
// -- field offset vector offset
// CHECK-SAME: i32 6,
-// -- field names
-// CHECK-SAME: [5 x i8]* [[DYNAMICWITHREQUIREMENTS_FIELDS]]
// -- generic parameter vector offset
// CHECK-SAME: i32 2,
// -- generic params, requirements, key args, extra args
diff --git a/test/IRGen/indirect_enum.sil b/test/IRGen/indirect_enum.sil
index 115a27a..8487e0b 100644
--- a/test/IRGen/indirect_enum.sil
+++ b/test/IRGen/indirect_enum.sil
@@ -5,39 +5,21 @@
// CHECK-64: @"$S13indirect_enum5TreeAOWV" = internal constant {{.*}} i8* inttoptr ([[WORD:i64]] 8 to i8*), i8* inttoptr (i64 2162695 to i8*), i8* inttoptr (i64 8 to i8*)
// CHECK-32: @"$S13indirect_enum5TreeAOWV" = internal constant {{.*}} i8* inttoptr ([[WORD:i32]] 4 to i8*), i8* inttoptr (i32 2162691 to i8*), i8* inttoptr (i32 4 to i8*)
-// CHECK-LABEL: define{{( protected)?}} private %swift.type** @get_field_types_TreeA
-// -- Leaf(T)
-// CHECK: [[BITS:%.*]] = ptrtoint %swift.type* %T to [[WORD]]
-// CHECK: [[INDIRECT_FLAG:%.*]] = or [[WORD]] [[BITS]], 1
-// -- Branch(TreeA, TreeA)
-// CHECK: [[TUPLE:%.*]] = call %swift.type* @swift_getTupleTypeMetadata2
-// CHECK: [[BITS:%.*]] = ptrtoint %swift.type* [[TUPLE]]
-// CHECK: [[INDIRECT_FLAG:%.*]] = or [[WORD]] [[BITS]], 1
+// CHECK-NOT: define{{( protected)?}} private %swift.type** @get_field_types_TreeA
indirect enum TreeA<T> {
case Nil
case Leaf(T)
case Branch(left: TreeA<T>, right: TreeA<T>)
}
-// CHECK-LABEL: define{{( protected)?}} private %swift.type** @get_field_types_TreeB
-// -- Leaf(T)
-// CHECK-NOT: ptrtoint %swift.type* %T
-// -- Branch(TreeA, TreeA)
-// CHECK: [[TUPLE:%.*]] = call %swift.type* @swift_getTupleTypeMetadata2
-// CHECK: [[BITS:%.*]] = ptrtoint %swift.type* [[TUPLE]]
-// CHECK: [[INDIRECT_FLAG:%.*]] = or [[WORD]] [[BITS]], 1
+// CHECK-NOT: define{{( protected)?}} private %swift.type** @get_field_types_TreeB
enum TreeB<T> {
case Nil
case Leaf(T)
indirect case Branch(left: TreeB<T>, right: TreeB<T>)
}
-// CHECK-LABEL: define{{( protected)?}} private %swift.type** @get_field_types_Foo
-// -- Foo(Int)
-// CHECK-64: (i64 or (i64 ptrtoint (%swift.type* @"$SSiN" {{.*}}), [[WORD]] 1)
-// CHECK-32: (i32 or (i32 ptrtoint (%swift.type* @"$SSiN" {{.*}}), [[WORD]] 1)
-// -- Bar(T)
-// CHECK-NOT: ptrtoint %swift.type* %T
+// CHECK-NOT: define{{( protected)?}} private %swift.type** @get_field_types_Foo
enum Foo<T> {
indirect case Foo(Int)
case Bar(T)
diff --git a/test/stdlib/Runtime.swift.gyb b/test/stdlib/Runtime.swift.gyb
index db0053a..e386aac 100644
--- a/test/stdlib/Runtime.swift.gyb
+++ b/test/stdlib/Runtime.swift.gyb
@@ -803,9 +803,11 @@
" - a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Plus\n" +
" - a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.SE30\n" +
" ▿ a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Classic\n" +
- " - Classic: 16\n" +
+ " ▿ Classic: (1 element)\n" +
+ " - mhz: 16\n" +
" ▿ a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Performa\n" +
- " - Performa: 220\n"
+ " ▿ Performa: (1 element)\n" +
+ " - model: 220\n"
expectEqual(expected, output)
}
@@ -849,11 +851,13 @@
" - a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.MacPaint\n" +
" - a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.FileMaker\n" +
" ▿ a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.ClarisWorks\n" +
- " ▿ ClarisWorks: a.Floppy #0\n" +
- " - capacity: 800\n" +
+ " ▿ ClarisWorks: (1 element)\n" +
+ " ▿ floppy: a.Floppy #0\n" +
+ " - capacity: 800\n" +
" ▿ a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.HyperCard\n" +
- " ▿ HyperCard: a.CDROM #1\n" +
- " - capacity: 600\n"
+ " ▿ HyperCard: (1 element)\n" +
+ " ▿ cdrom: a.CDROM #1\n" +
+ " - capacity: 600\n"
expectEqual(expected, output)
}
@@ -885,9 +889,11 @@
" - a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.MacPaint\n" +
" - a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.FileMaker\n" +
" ▿ a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.ClarisWorks\n" +
- " - ClarisWorks: true\n" +
+ " ▿ ClarisWorks: (1 element)\n" +
+ " - floppy: true\n" +
" ▿ a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.HyperCard\n" +
- " - HyperCard: false\n"
+ " ▿ HyperCard: (1 element)\n" +
+ " - cdrom: false\n"
expectEqual(expected, output)
}
@@ -920,9 +926,11 @@
" - a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.IIe\n" +
" - a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.IIgs\n" +
" ▿ a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.Centris\n" +
- " - Centris: 4096\n" +
+ " ▿ Centris: (1 element)\n" +
+ " - ram: 4096\n" +
" ▿ a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.Quadra\n" +
- " - Quadra: \"160MB\"\n" +
+ " ▿ Quadra: (1 element)\n" +
+ " - hdd: \"160MB\"\n" +
" - a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.PowerBook170\n" +
" - a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.PowerBookDuo220\n"
diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp
index 3057489..2c7ae2d 100644
--- a/tools/swift-ide-test/swift-ide-test.cpp
+++ b/tools/swift-ide-test/swift-ide-test.cpp
@@ -1611,18 +1611,21 @@
case NodeKind::Structure:
case NodeKind::Class:
case NodeKind::Enum:
+ case NodeKind::OtherNominalType:
break;
case NodeKind::BoundGenericStructure:
case NodeKind::BoundGenericClass:
case NodeKind::BoundGenericEnum:
+ case NodeKind::BoundGenericOtherNominalType:
// Base type
typeNode = node->getFirstChild();
// Nominal type
node = typeNode->getFirstChild();
assert(node->getKind() == NodeKind::Structure ||
node->getKind() == NodeKind::Class ||
- node->getKind() == NodeKind::Enum);
+ node->getKind() == NodeKind::Enum ||
+ node->getKind() == NodeKind::OtherNominalType);
break;
default: