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 &section : cache.DynamicSections) {
+    for (const auto *descriptor : section) {
+      if (isRequestedDescriptor(*descriptor))
+        return;
+    }
+  }
+
+  for (const auto &section : 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: