]> granicus.if.org Git - llvm/commitdiff
[CodeView] Hook up CodeViewRecordIO to type serialization path.
authorZachary Turner <zturner@google.com>
Tue, 8 Nov 2016 22:24:53 +0000 (22:24 +0000)
committerZachary Turner <zturner@google.com>
Tue, 8 Nov 2016 22:24:53 +0000 (22:24 +0000)
Previously support had been added for using CodeViewRecordIO
to read (deserialize) CodeView type records.  This patch adds
support for writing those same records.  With this patch,
reading and writing of CodeView type records finally uses a single
codepath.

Differential Revision: https://reviews.llvm.org/D26253

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@286304 91177308-0d34-0410-b5e6-96231b3b80d8

37 files changed:
include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h
include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h [deleted file]
include/llvm/DebugInfo/CodeView/ListRecordBuilder.h [deleted file]
include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h [deleted file]
include/llvm/DebugInfo/CodeView/MethodListRecordBuilder.h [deleted file]
include/llvm/DebugInfo/CodeView/RecordSerialization.h
include/llvm/DebugInfo/CodeView/TypeDeserializer.h
include/llvm/DebugInfo/CodeView/TypeIndex.h
include/llvm/DebugInfo/CodeView/TypeRecord.h
include/llvm/DebugInfo/CodeView/TypeRecordMapping.h
include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h [deleted file]
include/llvm/DebugInfo/CodeView/TypeSerializer.h [new file with mode: 0644]
include/llvm/DebugInfo/CodeView/TypeTableBuilder.h
include/llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h
include/llvm/DebugInfo/MSF/StreamWriter.h
lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
lib/CodeGen/AsmPrinter/CodeViewDebug.h
lib/DebugInfo/CodeView/CMakeLists.txt
lib/DebugInfo/CodeView/CVTypeVisitor.cpp
lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp [deleted file]
lib/DebugInfo/CodeView/ListRecordBuilder.cpp [deleted file]
lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp [deleted file]
lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp [deleted file]
lib/DebugInfo/CodeView/TypeDumper.cpp
lib/DebugInfo/CodeView/TypeRecordBuilder.cpp [deleted file]
lib/DebugInfo/CodeView/TypeRecordMapping.cpp
lib/DebugInfo/CodeView/TypeSerializer.cpp [new file with mode: 0644]
lib/DebugInfo/CodeView/TypeStreamMerger.cpp
lib/DebugInfo/CodeView/TypeTableBuilder.cpp [deleted file]
tools/llvm-pdbdump/PdbYaml.cpp
tools/llvm-pdbdump/YamlSerializationContext.h
tools/llvm-pdbdump/YamlTypeDumper.cpp
tools/llvm-pdbdump/YamlTypeDumper.h
tools/llvm-readobj/COFFDumper.cpp
tools/llvm-readobj/ObjDumper.h
tools/llvm-readobj/llvm-readobj.cpp

index 3a6a5b2d9344f85bf29006f2ef3e2a7c1c69fc1a..cee26a1daf10c666b8ca8b29417144f26c75ff59 100644 (file)
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/MSF/StreamReader.h"
 #include "llvm/DebugInfo/MSF/StreamWriter.h"
 #include "llvm/Support/Error.h"
 
-#include <stdint.h>
 #include <type_traits>
 
+#include <stdint.h>
+
 namespace llvm {
-namespace msf {
-class StreamReader;
-class StreamWriter;
-}
 namespace codeview {
 
 class CodeViewRecordIO {
-  struct ActiveRecord {
-    uint16_t Kind;
-  };
+  uint32_t getCurrentOffset() const {
+    return (isWriting()) ? Writer->getOffset() : Reader->getOffset();
+  }
 
 public:
   explicit CodeViewRecordIO(msf::StreamReader &Reader) : Reader(&Reader) {}
   explicit CodeViewRecordIO(msf::StreamWriter &Writer) : Writer(&Writer) {}
 
-  Error beginRecord(uint16_t Kind);
+  Error beginRecord(Optional<uint32_t> MaxLength);
   Error endRecord();
+
   Error mapInteger(TypeIndex &TypeInd);
 
   bool isReading() const { return Reader != nullptr; }
   bool isWriting() const { return !isReading(); }
 
+  uint32_t maxFieldLength() const;
+
   template <typename T> Error mapInteger(T &Value) {
     if (isWriting())
       return Writer->writeInteger(Value);
@@ -53,6 +55,9 @@ public:
   }
 
   template <typename T> Error mapEnum(T &Value) {
+    if (sizeof(Value) > maxFieldLength())
+      return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
     using U = typename std::underlying_type<T>::type;
     U X;
     if (isWriting())
@@ -124,7 +129,23 @@ private:
   Error writeEncodedSignedInteger(const int64_t &Value);
   Error writeEncodedUnsignedInteger(const uint64_t &Value);
 
-  Optional<ActiveRecord> CurrentRecord;
+  struct RecordLimit {
+    uint32_t BeginOffset;
+    Optional<uint32_t> MaxLength;
+
+    Optional<uint32_t> bytesRemaining(uint32_t CurrentOffset) const {
+      if (!MaxLength.hasValue())
+        return None;
+      assert(CurrentOffset >= BeginOffset);
+
+      uint32_t BytesUsed = CurrentOffset - BeginOffset;
+      if (BytesUsed >= *MaxLength)
+        return 0;
+      return *MaxLength - BytesUsed;
+    }
+  };
+
+  SmallVector<RecordLimit, 2> Limits;
 
   msf::StreamReader *Reader = nullptr;
   msf::StreamWriter *Writer = nullptr;
diff --git a/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h b/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h
deleted file mode 100644 (file)
index f320153..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-//===- FieldListRecordBuilder.h ---------------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H
-#define LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H
-
-#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-
-namespace llvm {
-namespace codeview {
-
-class MethodInfo {
-public:
-  MethodInfo() : Access(), Kind(), Options(), Type(), VTableSlotOffset(-1) {}
-
-  MethodInfo(MemberAccess Access, MethodKind Kind, MethodOptions Options,
-             TypeIndex Type, int32_t VTableSlotOffset)
-      : Access(Access), Kind(Kind), Options(Options), Type(Type),
-        VTableSlotOffset(VTableSlotOffset) {}
-
-  MemberAccess getAccess() const { return Access; }
-  MethodKind getKind() const { return Kind; }
-  MethodOptions getOptions() const { return Options; }
-  TypeIndex getType() const { return Type; }
-  int32_t getVTableSlotOffset() const { return VTableSlotOffset; }
-
-private:
-  MemberAccess Access;
-  MethodKind Kind;
-  MethodOptions Options;
-  TypeIndex Type;
-  int32_t VTableSlotOffset;
-};
-
-class FieldListRecordBuilder : public ListRecordBuilder {
-private:
-  FieldListRecordBuilder(const FieldListRecordBuilder &) = delete;
-  void operator=(const FieldListRecordBuilder &) = delete;
-
-public:
-  FieldListRecordBuilder();
-
-  void reset() { ListRecordBuilder::reset(); }
-
-  void writeMemberType(const BaseClassRecord &Record);
-  void writeMemberType(const EnumeratorRecord &Record);
-  void writeMemberType(const DataMemberRecord &Record);
-  void writeMemberType(const OneMethodRecord &Record);
-  void writeMemberType(const OverloadedMethodRecord &Record);
-  void writeMemberType(const NestedTypeRecord &Record);
-  void writeMemberType(const StaticDataMemberRecord &Record);
-  void writeMemberType(const VirtualBaseClassRecord &Record);
-  void writeMemberType(const VFPtrRecord &Type);
-
-  using ListRecordBuilder::writeMemberType;
-};
-}
-}
-
-#endif
diff --git a/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h b/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h
deleted file mode 100644 (file)
index d75158f..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-//===- ListRecordBuilder.h --------------------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_DEBUGINFO_CODEVIEW_LISTRECORDBUILDER_H
-#define LLVM_DEBUGINFO_CODEVIEW_LISTRECORDBUILDER_H
-
-#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
-
-namespace llvm {
-namespace codeview {
-class TypeTableBuilder;
-
-class ListRecordBuilder {
-private:
-  ListRecordBuilder(const ListRecordBuilder &) = delete;
-  ListRecordBuilder &operator=(const ListRecordBuilder &) = delete;
-
-protected:
-  const int MethodKindShift = 2;
-
-  explicit ListRecordBuilder(TypeRecordKind Kind);
-
-public:
-  llvm::StringRef str() { return Builder.str(); }
-
-  void reset() {
-    Builder.reset(Kind);
-    ContinuationOffsets.clear();
-    SubrecordStart = 0;
-  }
-
-  void writeMemberType(const ListContinuationRecord &R);
-
-  /// Writes this list record as a possible sequence of records.
-  TypeIndex writeListRecord(TypeTableBuilder &Table);
-
-protected:
-  void finishSubRecord();
-
-  TypeRecordBuilder &getBuilder() { return Builder; }
-
-private:
-  size_t getLastContinuationStart() const {
-    return ContinuationOffsets.empty() ? 0 : ContinuationOffsets.back();
-  }
-  size_t getLastContinuationEnd() const { return Builder.size(); }
-  size_t getLastContinuationSize() const {
-    return getLastContinuationEnd() - getLastContinuationStart();
-  }
-
-  TypeRecordKind Kind;
-  TypeRecordBuilder Builder;
-  SmallVector<size_t, 4> ContinuationOffsets;
-  size_t SubrecordStart = 0;
-};
-}
-}
-
-#endif
diff --git a/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h
deleted file mode 100644 (file)
index d72bd30..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-//===- MemoryTypeTableBuilder.h ---------------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
-#define LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include <vector>
-
-namespace llvm {
-namespace codeview {
-
-class MemoryTypeTableBuilder : public TypeTableBuilder {
-public:
-  explicit MemoryTypeTableBuilder(BumpPtrAllocator &Allocator)
-      : RecordStorage(Allocator) {}
-
-  bool empty() const { return Records.empty(); }
-
-  template <typename TFunc> void ForEachRecord(TFunc Func) {
-    uint32_t Index = TypeIndex::FirstNonSimpleIndex;
-
-    for (StringRef R : Records) {
-      Func(TypeIndex(Index), R);
-      ++Index;
-    }
-  }
-
-  TypeIndex writeRecord(llvm::StringRef Data) override;
-
-  ArrayRef<StringRef> getRecords() const { return Records; }
-
-private:
-  std::vector<StringRef> Records;
-  BumpPtrAllocator &RecordStorage;
-  DenseMap<StringRef, TypeIndex> HashedRecords;
-};
-
-} // end namespace codeview
-} // end namespace llvm
-
-#endif // LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
diff --git a/include/llvm/DebugInfo/CodeView/MethodListRecordBuilder.h b/include/llvm/DebugInfo/CodeView/MethodListRecordBuilder.h
deleted file mode 100644 (file)
index faa404d..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-//===- MethodListRecordBuilder.h --------------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_DEBUGINFO_CODEVIEW_METHODLISTRECORDBUILDER_H
-#define LLVM_DEBUGINFO_CODEVIEW_METHODLISTRECORDBUILDER_H
-
-#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
-
-namespace llvm {
-namespace codeview {
-
-class MethodInfo;
-
-class MethodListRecordBuilder : public ListRecordBuilder {
-private:
-  MethodListRecordBuilder(const MethodListRecordBuilder &) = delete;
-  MethodListRecordBuilder &operator=(const MethodListRecordBuilder &) = delete;
-
-public:
-  MethodListRecordBuilder();
-
-  void writeMethod(MemberAccess Access, MethodKind Kind, MethodOptions Options,
-                   TypeIndex Type, int32_t VTableSlotOffset);
-  void writeMethod(const MethodInfo &Method);
-};
-}
-}
-
-#endif
index a670bb420d8ada80aa2d324aaaf9c5707ff0a19e..97b6f561bb973becfea6ca6fab52320aa54eb25a 100644 (file)
@@ -32,7 +32,7 @@ using llvm::support::ulittle32_t;
 enum : unsigned { MaxRecordLength = 0xFF00 };
 
 struct RecordPrefix {
-  ulittle16_t RecordLen;  // Record length, starting from &Leaf.
+  ulittle16_t RecordLen;  // Record length, starting from &RecordKind.
   ulittle16_t RecordKind; // Record kind enum (SymRecordKind or TypeRecordKind)
 };
 
index b42d6951cb81fcb2c7e2d6a926d71f1f6a09da41..07ab464471d30efadcbffd75d8b59a1b67d62ae9 100644 (file)
@@ -76,7 +76,17 @@ class FieldListDeserializer : public TypeVisitorCallbacks {
   };
 
 public:
-  explicit FieldListDeserializer(msf::StreamReader &Reader) : Mapping(Reader) {}
+  explicit FieldListDeserializer(msf::StreamReader &Reader) : Mapping(Reader) {
+    CVType FieldList;
+    FieldList.Type = TypeLeafKind::LF_FIELDLIST;
+    consumeError(Mapping.Mapping.visitTypeBegin(FieldList));
+  }
+
+  ~FieldListDeserializer() {
+    CVType FieldList;
+    FieldList.Type = TypeLeafKind::LF_FIELDLIST;
+    consumeError(Mapping.Mapping.visitTypeEnd(FieldList));
+  }
 
   Error visitMemberBegin(CVMemberRecord &Record) override {
     Mapping.StartOffset = Mapping.Reader.getOffset();
index 29e3369f9e4c82b869a49f1e5692ea706f6cd79a..3c11d248fa721d305acd96c39679d28386b9bd49 100644 (file)
@@ -93,7 +93,7 @@ public:
   static const uint32_t SimpleModeMask = 0x00000700;
 
 public:
-  TypeIndex() : Index(0) {}
+  TypeIndex() : Index(static_cast<uint32_t>(SimpleTypeKind::None)) {}
   explicit TypeIndex(uint32_t Index) : Index(Index) {}
   explicit TypeIndex(SimpleTypeKind Kind)
       : Index(static_cast<uint32_t>(Kind)) {}
index 7b8a3f35a381b6ded5975e174c22c12d3300d006..e24a2739269f3b9f7e16360d6ee00fcaa39f890f 100644 (file)
@@ -701,26 +701,25 @@ public:
                   StringRef Name)
       : TypeRecord(TypeRecordKind::OneMethod), Type(Type), Attrs(Attrs),
         VFTableOffset(VFTableOffset), Name(Name) {}
-  OneMethodRecord(TypeIndex Type, MemberAccess Access, MethodKind Kind,
+  OneMethodRecord(TypeIndex Type, MemberAccess Access, MethodKind MK,
                   MethodOptions Options, int32_t VFTableOffset, StringRef Name)
       : TypeRecord(TypeRecordKind::OneMethod), Type(Type),
-        Attrs(Access, Kind, Options), VFTableOffset(VFTableOffset), Name(Name) {
-  }
+        Attrs(Access, MK, Options), VFTableOffset(VFTableOffset), Name(Name) {}
 
   /// Rewrite member type indices with IndexMap. Returns false if a type index
   /// is not in the map.
   bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
 
   TypeIndex getType() const { return Type; }
-  MethodKind getKind() const { return Attrs.getMethodKind(); }
+  MethodKind getMethodKind() const { return Attrs.getMethodKind(); }
   MethodOptions getOptions() const { return Attrs.getFlags(); }
   MemberAccess getAccess() const { return Attrs.getAccess(); }
   int32_t getVFTableOffset() const { return VFTableOffset; }
   StringRef getName() const { return Name; }
 
   bool isIntroducingVirtual() const {
-    return getKind() == MethodKind::IntroducingVirtual ||
-           getKind() == MethodKind::PureIntroducingVirtual;
+    return getMethodKind() == MethodKind::IntroducingVirtual ||
+           getMethodKind() == MethodKind::PureIntroducingVirtual;
   }
   TypeIndex Type;
   MemberAttributes Attrs;
index 970f345e0afb455a38ad6105e123ee31a2c890c4..fe470a72abbb15e80ac727bf070c0f1d07964779 100644 (file)
 #include "llvm/Support/Error.h"
 
 namespace llvm {
+namespace msf {
+class StreamReader;
+class StreamWriter;
+}
 namespace codeview {
 class TypeRecordMapping : public TypeVisitorCallbacks {
 public:
   explicit TypeRecordMapping(msf::StreamReader &Reader) : IO(Reader) {}
+  explicit TypeRecordMapping(msf::StreamWriter &Writer) : IO(Writer) {}
 
   Error visitTypeBegin(CVType &Record) override;
   Error visitTypeEnd(CVType &Record) override;
@@ -37,6 +42,7 @@ public:
 
 private:
   Optional<TypeLeafKind> TypeKind;
+  Optional<TypeLeafKind> MemberKind;
 
   CodeViewRecordIO IO;
 };
diff --git a/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h b/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h
deleted file mode 100644 (file)
index e6b6f25..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-//===- TypeSerializationVisitor.h -------------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZATIONVISITOR_H
-#define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZATIONVISITOR_H
-
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-namespace codeview {
-
-class TypeSerializationVisitor : public TypeVisitorCallbacks {
-public:
-  TypeSerializationVisitor(FieldListRecordBuilder &FieldListBuilder,
-                           MemoryTypeTableBuilder &TypeTableBuilder)
-      : FieldListBuilder(FieldListBuilder), TypeTableBuilder(TypeTableBuilder) {
-  }
-
-  virtual Error visitTypeBegin(CVType &Record) override {
-    if (Record.Type == TypeLeafKind::LF_FIELDLIST)
-      FieldListBuilder.reset();
-    return Error::success();
-  }
-
-  virtual Error visitTypeEnd(CVType &Record) override {
-    // Since this visitor's purpose is to serialize the record, fill out the
-    // fields of `Record` with the bytes of the record.
-    if (Record.Type == TypeLeafKind::LF_FIELDLIST) {
-      TypeTableBuilder.writeFieldList(FieldListBuilder);
-      updateCVRecord(Record);
-    }
-
-    return Error::success();
-  }
-
-#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
-  virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
-    visitKnownRecordImpl(CVR, Record);                                         \
-    return Error::success();                                                   \
-  }
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
-  virtual Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record)    \
-      override {                                                               \
-    visitMemberRecordImpl(Record);                                             \
-    return Error::success();                                                   \
-  }
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
-
-private:
-  void updateCVRecord(CVType &Record) {
-    StringRef S = TypeTableBuilder.getRecords().back();
-    Record.RecordData = ArrayRef<uint8_t>(S.bytes_begin(), S.bytes_end());
-  }
-  template <typename RecordKind>
-  void visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
-    TypeTableBuilder.writeKnownType(Record);
-    updateCVRecord(CVR);
-  }
-  template <typename RecordKind>
-  void visitMemberRecordImpl(RecordKind &Record) {
-    FieldListBuilder.writeMemberType(Record);
-  }
-
-  void visitKnownRecordImpl(CVType &CVR, FieldListRecord &FieldList) {}
-
-  FieldListRecordBuilder &FieldListBuilder;
-  MemoryTypeTableBuilder &TypeTableBuilder;
-};
-}
-}
-
-#endif
diff --git a/include/llvm/DebugInfo/CodeView/TypeSerializer.h b/include/llvm/DebugInfo/CodeView/TypeSerializer.h
new file mode 100644 (file)
index 0000000..e059221
--- /dev/null
@@ -0,0 +1,140 @@
+//===- TypeSerializer.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
+
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/DebugInfo/MSF/StreamWriter.h"
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+namespace codeview {
+
+class TypeSerializer : public TypeVisitorCallbacks {
+  struct SubRecord {
+    SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {}
+
+    TypeLeafKind Kind;
+    uint32_t Size = 0;
+  };
+  struct RecordSegment {
+    SmallVector<SubRecord, 16> SubRecords;
+
+    uint32_t length() const {
+      uint32_t L = sizeof(RecordPrefix);
+      for (const auto &R : SubRecords) {
+        L += R.Size;
+      }
+      return L;
+    }
+  };
+
+  typedef SmallVector<MutableArrayRef<uint8_t>, 2> RecordList;
+
+  static constexpr uint8_t ContinuationLength = 8;
+  BumpPtrAllocator &RecordStorage;
+  RecordSegment CurrentSegment;
+  RecordList FieldListSegments;
+
+  TypeIndex LastTypeIndex;
+  Optional<TypeLeafKind> TypeKind;
+  Optional<TypeLeafKind> MemberKind;
+  std::vector<uint8_t> RecordBuffer;
+  msf::MutableByteStream Stream;
+  msf::StreamWriter Writer;
+  TypeRecordMapping Mapping;
+
+  RecordList SeenRecords;
+  StringMap<TypeIndex> HashedRecords;
+
+  bool isInFieldList() const;
+  TypeIndex calcNextTypeIndex() const;
+  TypeIndex incrementTypeIndex();
+  MutableArrayRef<uint8_t> getCurrentSubRecordData();
+  MutableArrayRef<uint8_t> getCurrentRecordData();
+  Error writeRecordPrefix(TypeLeafKind Kind);
+  TypeIndex insertRecordBytesPrivate(MutableArrayRef<uint8_t> Record);
+
+  Expected<MutableArrayRef<uint8_t>>
+  addPadding(MutableArrayRef<uint8_t> Record);
+
+public:
+  explicit TypeSerializer(BumpPtrAllocator &Storage);
+
+  ArrayRef<MutableArrayRef<uint8_t>> records() const;
+  TypeIndex getLastTypeIndex() const;
+  TypeIndex insertRecordBytes(MutableArrayRef<uint8_t> Record);
+  Expected<TypeIndex> visitTypeEndGetIndex(CVType &Record);
+
+  Error visitTypeBegin(CVType &Record) override;
+  Error visitTypeEnd(CVType &Record) override;
+  Error visitMemberBegin(CVMemberRecord &Record) override;
+  Error visitMemberEnd(CVMemberRecord &Record) override;
+
+#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
+  virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
+    return visitKnownRecordImpl(CVR, Record);                                  \
+  }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
+  Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
+    return visitKnownMemberImpl<Name##Record>(CVR, Record);                    \
+  }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+
+private:
+  template <typename RecordKind>
+  Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
+    return Mapping.visitKnownRecord(CVR, Record);
+  }
+
+  template <typename RecordType>
+  Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
+    assert(CVR.Kind == static_cast<TypeLeafKind>(Record.getKind()));
+
+    if (auto EC = Writer.writeEnum(CVR.Kind))
+      return EC;
+
+    if (auto EC = Mapping.visitKnownMember(CVR, Record))
+      return EC;
+
+    // Get all the data that was just written and is yet to be committed to
+    // the current segment.  Then pad it to 4 bytes.
+    MutableArrayRef<uint8_t> ThisRecord = getCurrentSubRecordData();
+    auto ExpectedRecord = addPadding(ThisRecord);
+    if (!ExpectedRecord)
+      return ExpectedRecord.takeError();
+    ThisRecord = *ExpectedRecord;
+
+    CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size());
+    CVR.Data = ThisRecord;
+
+    // Both the last subrecord and the total length of this segment should be
+    // multiples of 4.
+    assert(ThisRecord.size() % 4 == 0);
+    assert(CurrentSegment.length() % 4 == 0);
+
+    return Error::success();
+  }
+};
+}
+}
+
+#endif
index cab1c6d6f5b6bfbb0fec695fe7c22bb93c35e889..02178669a163babf4768640e070b31e4e9e9a815 100644 (file)
 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H
 #define LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H
 
-#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/Support/Compiler.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
 
 namespace llvm {
 
-class StringRef;
-
 namespace codeview {
 
-class FieldListRecordBuilder;
-class MethodListRecordBuilder;
-class TypeRecordBuilder;
-
 class TypeTableBuilder {
 private:
   TypeTableBuilder(const TypeTableBuilder &) = delete;
   TypeTableBuilder &operator=(const TypeTableBuilder &) = delete;
 
-protected:
-  TypeTableBuilder();
+  TypeIndex handleError(llvm::Error EC) const {
+    assert(false && "Couldn't write Type!");
+    llvm::consumeError(std::move(EC));
+    return TypeIndex();
+  }
 
-public:
-  virtual ~TypeTableBuilder();
+  BumpPtrAllocator &Allocator;
+  TypeSerializer Serializer;
 
 public:
-  TypeIndex writeKnownType(const ModifierRecord &Record);
-  TypeIndex writeKnownType(const ProcedureRecord &Record);
-  TypeIndex writeKnownType(const MemberFunctionRecord &Record);
-  TypeIndex writeKnownType(const ArgListRecord &Record);
-  TypeIndex writeKnownType(const PointerRecord &Record);
-  TypeIndex writeKnownType(const ArrayRecord &Record);
-  TypeIndex writeKnownType(const ClassRecord &Record);
-  TypeIndex writeKnownType(const UnionRecord &Record);
-  TypeIndex writeKnownType(const EnumRecord &Record);
-  TypeIndex writeKnownType(const BitFieldRecord &Record);
-  TypeIndex writeKnownType(const VFTableShapeRecord &Record);
-  TypeIndex writeKnownType(const StringIdRecord &Record);
-  TypeIndex writeKnownType(const VFTableRecord &Record);
-  TypeIndex writeKnownType(const UdtSourceLineRecord &Record);
-  TypeIndex writeKnownType(const UdtModSourceLineRecord &Record);
-  TypeIndex writeKnownType(const FuncIdRecord &Record);
-  TypeIndex writeKnownType(const MemberFuncIdRecord &Record);
-  TypeIndex writeKnownType(const BuildInfoRecord &Record);
-  TypeIndex writeKnownType(const MethodOverloadListRecord &Record);
-  TypeIndex writeKnownType(const TypeServer2Record &Record);
-
-  TypeIndex writeFieldList(FieldListRecordBuilder &FieldList);
-
-  TypeIndex writeRecord(TypeRecordBuilder &builder);
-
-  virtual TypeIndex writeRecord(llvm::StringRef record) = 0;
-
-  ArrayRef<TypeRecordKind> getRecordKinds() const { return RecordKinds; }
+  explicit TypeTableBuilder(BumpPtrAllocator &Allocator)
+      : Allocator(Allocator), Serializer(Allocator) {}
 
-private:
-  std::vector<TypeRecordKind> RecordKinds;
+  bool empty() const { return Serializer.records().empty(); }
+
+  BumpPtrAllocator &getAllocator() const { return Allocator; }
+
+  template <typename T> TypeIndex writeKnownType(T &Record) {
+    static_assert(!std::is_same<T, FieldListRecord>::value,
+                  "Can't serialize FieldList!");
+
+    CVType Type;
+    Type.Type = static_cast<TypeLeafKind>(Record.getKind());
+    if (auto EC = Serializer.visitTypeBegin(Type))
+      return handleError(std::move(EC));
+    if (auto EC = Serializer.visitKnownRecord(Type, Record))
+      return handleError(std::move(EC));
+
+    auto ExpectedIndex = Serializer.visitTypeEndGetIndex(Type);
+    if (!ExpectedIndex)
+      return handleError(ExpectedIndex.takeError());
+
+    return *ExpectedIndex;
+  }
+
+  TypeIndex writeSerializedRecord(MutableArrayRef<uint8_t> Record) {
+    return Serializer.insertRecordBytes(Record);
+  }
+
+  template <typename TFunc> void ForEachRecord(TFunc Func) {
+    uint32_t Index = TypeIndex::FirstNonSimpleIndex;
+
+    for (auto Record : Serializer.records()) {
+      Func(TypeIndex(Index), Record);
+      ++Index;
+    }
+  }
+
+  ArrayRef<MutableArrayRef<uint8_t>> records() const {
+    return Serializer.records();
+  }
+};
+
+class FieldListRecordBuilder {
+  TypeTableBuilder &TypeTable;
+  TypeSerializer TempSerializer;
+  CVType Type;
+
+public:
+  explicit FieldListRecordBuilder(TypeTableBuilder &TypeTable)
+      : TypeTable(TypeTable), TempSerializer(TypeTable.getAllocator()) {
+    Type.Type = TypeLeafKind::LF_FIELDLIST;
+  }
+
+  void begin() {
+    if (auto EC = TempSerializer.visitTypeBegin(Type))
+      consumeError(std::move(EC));
+  }
+
+  template <typename T> void writeMemberType(T &Record) {
+    CVMemberRecord CVMR;
+    CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind());
+    if (auto EC = TempSerializer.visitMemberBegin(CVMR))
+      consumeError(std::move(EC));
+    if (auto EC = TempSerializer.visitKnownMember(CVMR, Record))
+      consumeError(std::move(EC));
+    if (auto EC = TempSerializer.visitMemberEnd(CVMR))
+      consumeError(std::move(EC));
+  }
+
+  TypeIndex end() {
+    if (auto EC = TempSerializer.visitTypeEnd(Type)) {
+      consumeError(std::move(EC));
+      return TypeIndex();
+    }
+
+    TypeIndex Index;
+    for (auto Record : TempSerializer.records()) {
+      Index = TypeTable.writeSerializedRecord(Record);
+    }
+    return Index;
+  }
 };
 }
 }
index 832307f4fb37e78aa2e7fd7eef58a6ccb6df4a82..4f43b2240f4765a6b28642f59ec609f728057af4 100644 (file)
@@ -74,26 +74,34 @@ public:
 
 #define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
   Error visitKnownRecord(CVType &CVR, Name##Record &Record) override {         \
-    for (auto Visitor : Pipeline) {                                            \
-      if (auto EC = Visitor->visitKnownRecord(CVR, Record))                    \
-        return EC;                                                             \
-    }                                                                          \
-    return Error::success();                                                   \
+    return visitKnownRecordImpl(CVR, Record);                                  \
   }
 #define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
   Error visitKnownMember(CVMemberRecord &CVMR, Name##Record &Record)           \
       override {                                                               \
-    for (auto Visitor : Pipeline) {                                            \
-      if (auto EC = Visitor->visitKnownMember(CVMR, Record))                   \
-        return EC;                                                             \
-    }                                                                          \
-    return Error::success();                                                   \
+    return visitKnownMemberImpl(CVMR, Record);                                 \
   }
 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
 
 private:
+  template <typename T> Error visitKnownRecordImpl(CVType &CVR, T &Record) {
+    for (auto Visitor : Pipeline) {
+      if (auto EC = Visitor->visitKnownRecord(CVR, Record))
+        return EC;
+    }
+    return Error::success();
+  }
+
+  template <typename T>
+  Error visitKnownMemberImpl(CVMemberRecord &CVMR, T &Record) {
+    for (auto Visitor : Pipeline) {
+      if (auto EC = Visitor->visitKnownMember(CVMR, Record))
+        return EC;
+    }
+    return Error::success();
+  }
   std::vector<TypeVisitorCallbacks *> Pipeline;
 };
 }
index 1b3bc32d6ac83fe49912d752f6d2d8169735aa9a..055cd9d42238d742e19ce3752437d6074a35e75d 100644 (file)
@@ -26,7 +26,7 @@ namespace msf {
 class StreamWriter {
 public:
   StreamWriter() {}
-  StreamWriter(WritableStreamRef Stream);
+  explicit StreamWriter(WritableStreamRef Stream);
 
   Error writeBytes(ArrayRef<uint8_t> Buffer);
   Error writeInteger(uint8_t Int);
index aa7a301687fd9a7135de28648e243bdce0cb9b33..88883fdd4488b3830c1486feccf960b646e49910 100644 (file)
@@ -15,7 +15,6 @@
 #include "llvm/ADT/TinyPtrVector.h"
 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
 #include "llvm/DebugInfo/CodeView/Line.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
 #include "llvm/DebugInfo/CodeView/TypeDumper.h"
@@ -222,8 +221,8 @@ TypeIndex CodeViewDebug::getScopeIndex(const DIScope *Scope) {
 
   // Build the fully qualified name of the scope.
   std::string ScopeName = getFullyQualifiedName(Scope);
-  TypeIndex TI =
-      TypeTable.writeKnownType(StringIdRecord(TypeIndex(), ScopeName));
+  StringIdRecord SID(TypeIndex(), ScopeName);
+  auto TI = TypeTable.writeKnownType(SID);
   return recordTypeIndexForDINode(Scope, TI);
 }
 
@@ -469,47 +468,47 @@ void CodeViewDebug::emitTypeInformation() {
   }
 
   CVTypeDumper CVTD(nullptr, /*PrintRecordBytes=*/false);
-  TypeTable.ForEachRecord(
-      [&](TypeIndex Index, StringRef Record) {
-        if (OS.isVerboseAsm()) {
-          // Emit a block comment describing the type record for readability.
-          SmallString<512> CommentBlock;
-          raw_svector_ostream CommentOS(CommentBlock);
-          ScopedPrinter SP(CommentOS);
-          SP.setPrefix(CommentPrefix);
-          CVTD.setPrinter(&SP);
-          Error E = CVTD.dump({Record.bytes_begin(), Record.bytes_end()});
-          if (E) {
-            logAllUnhandledErrors(std::move(E), errs(), "error: ");
-            llvm_unreachable("produced malformed type record");
-          }
-          // emitRawComment will insert its own tab and comment string before
-          // the first line, so strip off our first one. It also prints its own
-          // newline.
-          OS.emitRawComment(
-              CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
-        } else {
+  TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef<uint8_t> Record) {
+    if (OS.isVerboseAsm()) {
+      // Emit a block comment describing the type record for readability.
+      SmallString<512> CommentBlock;
+      raw_svector_ostream CommentOS(CommentBlock);
+      ScopedPrinter SP(CommentOS);
+      SP.setPrefix(CommentPrefix);
+      CVTD.setPrinter(&SP);
+      Error E = CVTD.dump(Record);
+      if (E) {
+        logAllUnhandledErrors(std::move(E), errs(), "error: ");
+        llvm_unreachable("produced malformed type record");
+      }
+      // emitRawComment will insert its own tab and comment string before
+      // the first line, so strip off our first one. It also prints its own
+      // newline.
+      OS.emitRawComment(
+          CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
+    } else {
 #ifndef NDEBUG
-          // Assert that the type data is valid even if we aren't dumping
-          // comments. The MSVC linker doesn't do much type record validation,
-          // so the first link of an invalid type record can succeed while
-          // subsequent links will fail with LNK1285.
-          ByteStream Stream({Record.bytes_begin(), Record.bytes_end()});
-          CVTypeArray Types;
-          StreamReader Reader(Stream);
-          Error E = Reader.readArray(Types, Reader.getLength());
-          if (!E) {
-            TypeVisitorCallbacks C;
-            E = CVTypeVisitor(C).visitTypeStream(Types);
-          }
-          if (E) {
-            logAllUnhandledErrors(std::move(E), errs(), "error: ");
-            llvm_unreachable("produced malformed type record");
-          }
+      // Assert that the type data is valid even if we aren't dumping
+      // comments. The MSVC linker doesn't do much type record validation,
+      // so the first link of an invalid type record can succeed while
+      // subsequent links will fail with LNK1285.
+      ByteStream Stream(Record);
+      CVTypeArray Types;
+      StreamReader Reader(Stream);
+      Error E = Reader.readArray(Types, Reader.getLength());
+      if (!E) {
+        TypeVisitorCallbacks C;
+        E = CVTypeVisitor(C).visitTypeStream(Types);
+      }
+      if (E) {
+        logAllUnhandledErrors(std::move(E), errs(), "error: ");
+        llvm_unreachable("produced malformed type record");
+      }
 #endif
-        }
-        OS.EmitBinaryData(Record);
-      });
+    }
+    StringRef S(reinterpret_cast<const char *>(Record.data()), Record.size());
+    OS.EmitBinaryData(S);
+  });
 }
 
 namespace {
@@ -1195,8 +1194,8 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
         (i == 0 && ElementSize == 0) ? Ty->getSizeInBits() / 8 : ElementSize;
 
     StringRef Name = (i == 0) ? Ty->getName() : "";
-    ElementTypeIndex = TypeTable.writeKnownType(
-        ArrayRecord(ElementTypeIndex, IndexType, ArraySize, Name));
+    ArrayRecord AR(ElementTypeIndex, IndexType, ArraySize, Name);
+    ElementTypeIndex = TypeTable.writeKnownType(AR);
   }
 
   (void)PartiallyIncomplete;
@@ -1421,7 +1420,8 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
       BaseTy = cast<DIDerivedType>(BaseTy)->getBaseType().resolve();
   }
   TypeIndex ModifiedTI = getTypeIndex(BaseTy);
-  return TypeTable.writeKnownType(ModifierRecord(ModifiedTI, Mods));
+  ModifierRecord MR(ModifiedTI, Mods);
+  return TypeTable.writeKnownType(MR);
 }
 
 TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
@@ -1478,9 +1478,10 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
   // TODO: Need to use the correct values for:
   //       FunctionOptions
   //       ThisPointerAdjustment.
-  TypeIndex TI = TypeTable.writeKnownType(MemberFunctionRecord(
-      ReturnTypeIndex, ClassType, ThisTypeIndex, CC, FunctionOptions::None,
-      ArgTypeIndices.size(), ArgListIndex, ThisAdjustment));
+  MemberFunctionRecord MFR(ReturnTypeIndex, ClassType, ThisTypeIndex, CC,
+                           FunctionOptions::None, ArgTypeIndices.size(),
+                           ArgListIndex, ThisAdjustment);
+  TypeIndex TI = TypeTable.writeKnownType(MFR);
 
   return TI;
 }
@@ -1488,7 +1489,9 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
 TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) {
   unsigned VSlotCount = Ty->getSizeInBits() / (8 * Asm->MAI->getPointerSize());
   SmallVector<VFTableSlotKind, 4> Slots(VSlotCount, VFTableSlotKind::Near);
-  return TypeTable.writeKnownType(VFTableShapeRecord(Slots));
+
+  VFTableShapeRecord VFTSR(Slots);
+  return TypeTable.writeKnownType(VFTSR);
 }
 
 static MemberAccess translateAccessFlags(unsigned RecordTag, unsigned Flags) {
@@ -1578,25 +1581,28 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) {
   if (Ty->isForwardDecl()) {
     CO |= ClassOptions::ForwardReference;
   } else {
-    FieldListRecordBuilder Fields;
+    FieldListRecordBuilder FLRB(TypeTable);
+
+    FLRB.begin();
     for (const DINode *Element : Ty->getElements()) {
       // We assume that the frontend provides all members in source declaration
       // order, which is what MSVC does.
       if (auto *Enumerator = dyn_cast_or_null<DIEnumerator>(Element)) {
-        Fields.writeMemberType(EnumeratorRecord(
-            MemberAccess::Public, APSInt::getUnsigned(Enumerator->getValue()),
-            Enumerator->getName()));
+        EnumeratorRecord ER(MemberAccess::Public,
+                            APSInt::getUnsigned(Enumerator->getValue()),
+                            Enumerator->getName());
+        FLRB.writeMemberType(ER);
         EnumeratorCount++;
       }
     }
-    FTI = TypeTable.writeFieldList(Fields);
+    FTI = FLRB.end();
   }
 
   std::string FullName = getFullyQualifiedName(Ty);
 
-  return TypeTable.writeKnownType(EnumRecord(EnumeratorCount, CO, FTI, FullName,
-                                             Ty->getIdentifier(),
-                                             getTypeIndex(Ty->getBaseType())));
+  EnumRecord ER(EnumeratorCount, CO, FTI, FullName, Ty->getIdentifier(),
+                getTypeIndex(Ty->getBaseType()));
+  return TypeTable.writeKnownType(ER);
 }
 
 //===----------------------------------------------------------------------===//
@@ -1695,9 +1701,9 @@ TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) {
   ClassOptions CO =
       ClassOptions::ForwardReference | getCommonClassOptions(Ty);
   std::string FullName = getFullyQualifiedName(Ty);
-  TypeIndex FwdDeclTI = TypeTable.writeKnownType(
-      ClassRecord(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0,
-                  FullName, Ty->getIdentifier()));
+  ClassRecord CR(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0,
+                 FullName, Ty->getIdentifier());
+  TypeIndex FwdDeclTI = TypeTable.writeKnownType(CR);
   if (!Ty->isForwardDecl())
     DeferredCompleteTypes.push_back(Ty);
   return FwdDeclTI;
@@ -1721,14 +1727,14 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) {
 
   uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
 
-  TypeIndex ClassTI = TypeTable.writeKnownType(
-      ClassRecord(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI,
-                  SizeInBytes, FullName, Ty->getIdentifier()));
+  ClassRecord CR(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI,
+                 SizeInBytes, FullName, Ty->getIdentifier());
+  TypeIndex ClassTI = TypeTable.writeKnownType(CR);
 
-  TypeTable.writeKnownType(UdtSourceLineRecord(
-      ClassTI, TypeTable.writeKnownType(StringIdRecord(
-                   TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
-      Ty->getLine()));
+  StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
+  TypeIndex SIDI = TypeTable.writeKnownType(SIDR);
+  UdtSourceLineRecord USLR(ClassTI, SIDI, Ty->getLine());
+  TypeTable.writeKnownType(USLR);
 
   addToUDTs(Ty, ClassTI);
 
@@ -1739,8 +1745,8 @@ TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) {
   ClassOptions CO =
       ClassOptions::ForwardReference | getCommonClassOptions(Ty);
   std::string FullName = getFullyQualifiedName(Ty);
-  TypeIndex FwdDeclTI = TypeTable.writeKnownType(
-      UnionRecord(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier()));
+  UnionRecord UR(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier());
+  TypeIndex FwdDeclTI = TypeTable.writeKnownType(UR);
   if (!Ty->isForwardDecl())
     DeferredCompleteTypes.push_back(Ty);
   return FwdDeclTI;
@@ -1760,13 +1766,14 @@ TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) {
   uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
   std::string FullName = getFullyQualifiedName(Ty);
 
-  TypeIndex UnionTI = TypeTable.writeKnownType(UnionRecord(
-      FieldCount, CO, FieldTI, SizeInBytes, FullName, Ty->getIdentifier()));
+  UnionRecord UR(FieldCount, CO, FieldTI, SizeInBytes, FullName,
+                 Ty->getIdentifier());
+  TypeIndex UnionTI = TypeTable.writeKnownType(UR);
 
-  TypeTable.writeKnownType(UdtSourceLineRecord(
-      UnionTI, TypeTable.writeKnownType(StringIdRecord(
-                   TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
-      Ty->getLine()));
+  StringIdRecord SIR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
+  TypeIndex SIRI = TypeTable.writeKnownType(SIR);
+  UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine());
+  TypeTable.writeKnownType(USLR);
 
   addToUDTs(Ty, UnionTI);
 
@@ -1781,7 +1788,8 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
   // list record.
   unsigned MemberCount = 0;
   ClassInfo Info = collectClassInfo(Ty);
-  FieldListRecordBuilder Fields;
+  FieldListRecordBuilder FLBR(TypeTable);
+  FLBR.begin();
 
   // Create base classes.
   for (const DIDerivedType *I : Info.Inheritance) {
@@ -1794,16 +1802,19 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
       auto RecordKind = (I->getFlags() & DINode::FlagIndirectVirtualBase) == DINode::FlagIndirectVirtualBase
                             ? TypeRecordKind::IndirectVirtualBaseClass
                             : TypeRecordKind::VirtualBaseClass;
-      Fields.writeMemberType(VirtualBaseClassRecord(
+      VirtualBaseClassRecord VBCR(
           RecordKind, translateAccessFlags(Ty->getTag(), I->getFlags()),
           getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset,
-          VBTableIndex));
+          VBTableIndex);
+
+      FLBR.writeMemberType(VBCR);
     } else {
       assert(I->getOffsetInBits() % 8 == 0 &&
              "bases must be on byte boundaries");
-      Fields.writeMemberType(BaseClassRecord(
-          translateAccessFlags(Ty->getTag(), I->getFlags()),
-          getTypeIndex(I->getBaseType()), I->getOffsetInBits() / 8));
+      BaseClassRecord BCR(translateAccessFlags(Ty->getTag(), I->getFlags()),
+                          getTypeIndex(I->getBaseType()),
+                          I->getOffsetInBits() / 8);
+      FLBR.writeMemberType(BCR);
     }
   }
 
@@ -1816,8 +1827,8 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
         translateAccessFlags(Ty->getTag(), Member->getFlags());
 
     if (Member->isStaticMember()) {
-      Fields.writeMemberType(
-          StaticDataMemberRecord(Access, MemberBaseType, MemberName));
+      StaticDataMemberRecord SDMR(Access, MemberBaseType, MemberName);
+      FLBR.writeMemberType(SDMR);
       MemberCount++;
       continue;
     }
@@ -1825,7 +1836,8 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
     // Virtual function pointer member.
     if ((Member->getFlags() & DINode::FlagArtificial) &&
         Member->getName().startswith("_vptr$")) {
-      Fields.writeMemberType(VFPtrRecord(getTypeIndex(Member->getBaseType())));
+      VFPtrRecord VFPR(getTypeIndex(Member->getBaseType()));
+      FLBR.writeMemberType(VFPR);
       MemberCount++;
       continue;
     }
@@ -1840,12 +1852,14 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
         MemberOffsetInBits = CI->getZExtValue() + MemberInfo.BaseOffset;
       }
       StartBitOffset -= MemberOffsetInBits;
-      MemberBaseType = TypeTable.writeKnownType(BitFieldRecord(
-          MemberBaseType, Member->getSizeInBits(), StartBitOffset));
+      BitFieldRecord BFR(MemberBaseType, Member->getSizeInBits(),
+                         StartBitOffset);
+      MemberBaseType = TypeTable.writeKnownType(BFR);
     }
     uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8;
-    Fields.writeMemberType(DataMemberRecord(Access, MemberBaseType,
-                                            MemberOffsetInBytes, MemberName));
+    DataMemberRecord DMR(Access, MemberBaseType, MemberOffsetInBytes,
+                         MemberName);
+    FLBR.writeMemberType(DMR);
     MemberCount++;
   }
 
@@ -1870,23 +1884,23 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
     }
     assert(Methods.size() > 0 && "Empty methods map entry");
     if (Methods.size() == 1)
-      Fields.writeMemberType(Methods[0]);
+      FLBR.writeMemberType(Methods[0]);
     else {
-      TypeIndex MethodList =
-          TypeTable.writeKnownType(MethodOverloadListRecord(Methods));
-      Fields.writeMemberType(
-          OverloadedMethodRecord(Methods.size(), MethodList, Name));
+      MethodOverloadListRecord MOLR(Methods);
+      TypeIndex MethodList = TypeTable.writeKnownType(MOLR);
+      OverloadedMethodRecord OMR(Methods.size(), MethodList, Name);
+      FLBR.writeMemberType(OMR);
     }
   }
 
   // Create nested classes.
   for (const DICompositeType *Nested : Info.NestedClasses) {
     NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName());
-    Fields.writeMemberType(R);
+    FLBR.writeMemberType(R);
     MemberCount++;
   }
 
-  TypeIndex FieldTI = TypeTable.writeFieldList(Fields);
+  TypeIndex FieldTI = FLBR.end();
   return std::make_tuple(FieldTI, Info.VShapeTI, MemberCount,
                          !Info.NestedClasses.empty());
 }
index 04551a4a1209323f48b27dd11c060ca0079e40a8..8c9cbd1d80ad17ad9651eae41f3950e311ad5e9e 100644 (file)
@@ -20,8 +20,8 @@
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DebugLoc.h"
 #include "llvm/MC/MCStreamer.h"
@@ -37,7 +37,7 @@ struct ClassInfo;
 class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
   MCStreamer &OS;
   llvm::BumpPtrAllocator Allocator;
-  codeview::MemoryTypeTableBuilder TypeTable;
+  codeview::TypeTableBuilder TypeTable;
 
   /// Represents the most general definition range.
   struct LocalVarDefRange {
index 4bbc48d111fa90b9bea94f07731e7258521d80e9..12675c3c6316c61b676f22b95d9ebf0af7770c2f 100644 (file)
@@ -4,21 +4,16 @@ add_llvm_library(LLVMDebugInfoCodeView
   CVSymbolVisitor.cpp
   CVTypeVisitor.cpp
   EnumTables.cpp
-  FieldListRecordBuilder.cpp
   Line.cpp
-  ListRecordBuilder.cpp
-  MemoryTypeTableBuilder.cpp
-  MethodListRecordBuilder.cpp
   ModuleSubstream.cpp
   ModuleSubstreamVisitor.cpp
   RecordSerialization.cpp
   SymbolDumper.cpp
   TypeDumper.cpp
   TypeRecord.cpp
-  TypeRecordBuilder.cpp
   TypeRecordMapping.cpp
+  TypeSerializer.cpp
   TypeStreamMerger.cpp
-  TypeTableBuilder.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView
index 5f5d5fe35ef2bdce02ffabc0898423a236e5a54e..5171e24f3aacce436afcd7a7f581c4ff9f32ede4 100644 (file)
 using namespace llvm;
 using namespace llvm::codeview;
 
-template <typename T>
-static Expected<CVMemberRecord>
-deserializeMemberRecord(FieldListDeserializer &Deserializer,
-                        msf::StreamReader &Reader, TypeLeafKind Kind) {
-  T MR(static_cast<TypeRecordKind>(Kind));
-  CVMemberRecord CVR;
-  CVR.Kind = Kind;
-
-  if (auto EC = Deserializer.visitMemberBegin(CVR))
-    return std::move(EC);
-  if (auto EC = Deserializer.visitKnownMember(CVR, MR))
-    return std::move(EC);
-  if (auto EC = Deserializer.visitMemberEnd(CVR))
-    return std::move(EC);
-
-  return CVR;
-}
-
 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
     : Callbacks(Callbacks) {}
 
@@ -85,7 +67,8 @@ Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
   return Error::success();
 }
 
-Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
+static Error visitMemberRecord(CVMemberRecord &Record,
+                               TypeVisitorCallbacks &Callbacks) {
   if (auto EC = Callbacks.visitMemberBegin(Record))
     return EC;
 
@@ -113,6 +96,10 @@ Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
   return Error::success();
 }
 
+Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
+  return ::visitMemberRecord(Record, Callbacks);
+}
+
 /// Visits the type records in Data. Sets the error flag on parse failures.
 Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
   for (auto I : Types) {
@@ -122,23 +109,6 @@ Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
   return Error::success();
 }
 
-template <typename MR>
-static Error visitKnownMember(FieldListDeserializer &Deserializer,
-                              msf::StreamReader &Reader, TypeLeafKind Leaf,
-                              TypeVisitorCallbacks &Callbacks) {
-  MR Record(static_cast<TypeRecordKind>(Leaf));
-  CVMemberRecord CVR;
-  CVR.Kind = Leaf;
-
-  if (auto EC = Callbacks.visitMemberBegin(CVR))
-    return EC;
-  if (auto EC = Callbacks.visitKnownMember(CVR, Record))
-    return EC;
-  if (auto EC = Callbacks.visitMemberEnd(CVR))
-    return EC;
-  return Error::success();
-}
-
 Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) {
   FieldListDeserializer Deserializer(Reader);
   TypeVisitorCallbackPipeline Pipeline;
@@ -150,25 +120,12 @@ Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) {
     if (auto EC = Reader.readEnum(Leaf))
       return EC;
 
-    CVType Record;
-    switch (Leaf) {
-    default:
-      // Field list records do not describe their own length, so we cannot
-      // continue parsing past a type that we don't know how to deserialize.
-      return llvm::make_error<CodeViewError>(
-          cv_error_code::unknown_member_record);
-#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
-  case EnumName: {                                                             \
-    if (auto EC = visitKnownMember<Name##Record>(Deserializer, Reader, Leaf,   \
-                                                 Pipeline))                    \
-      return EC;                                                               \
-    break;                                                                     \
-  }
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)                \
-  MEMBER_RECORD(EnumVal, EnumVal, AliasName)
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
-    }
+    CVMemberRecord Record;
+    Record.Kind = Leaf;
+    if (auto EC = ::visitMemberRecord(Record, Pipeline))
+      return EC;
   }
+
   return Error::success();
 }
 
index 7841e4f2f6aba49cdc29f9c479dcab330a677a22..19facaec9f076742f9788ebe58ad93ea7191e22f 100644 (file)
 using namespace llvm;
 using namespace llvm::codeview;
 
-Error CodeViewRecordIO::beginRecord(uint16_t Kind) {
-  assert(!CurrentRecord.hasValue() && "There is already a record active!");
-  CurrentRecord.emplace();
-
-  CurrentRecord->Kind = Kind;
+Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) {
+  RecordLimit Limit;
+  Limit.MaxLength = MaxLength;
+  Limit.BeginOffset = getCurrentOffset();
+  Limits.push_back(Limit);
   return Error::success();
 }
 
 Error CodeViewRecordIO::endRecord() {
-  assert(CurrentRecord.hasValue() && "Not in a record!");
-  CurrentRecord.reset();
+  assert(!Limits.empty() && "Not in a record!");
+  Limits.pop_back();
   return Error::success();
 }
 
+uint32_t CodeViewRecordIO::maxFieldLength() const {
+  assert(!Limits.empty() && "Not in a record!");
+
+  // The max length of the next field is the minimum of all lengths that would
+  // be allowed by any of the sub-records we're in.  In practice, we can only
+  // ever be at most 1 sub-record deep (in a FieldList), but this works for
+  // the general case.
+  uint32_t Offset = getCurrentOffset();
+  Optional<uint32_t> Min = Limits.front().bytesRemaining(Offset);
+  for (auto X : makeArrayRef(Limits).drop_front()) {
+    Optional<uint32_t> ThisMin = X.bytesRemaining(Offset);
+    if (ThisMin.hasValue())
+      Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin;
+  }
+  assert(Min.hasValue() && "Every field must have a maximum length!");
+
+  return *Min;
+}
+
 Error CodeViewRecordIO::skipPadding() {
   assert(!isWriting() && "Cannot skip padding while writing!");
 
@@ -114,7 +133,9 @@ Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value) {
 
 Error CodeViewRecordIO::mapStringZ(StringRef &Value) {
   if (isWriting()) {
-    if (auto EC = Writer->writeZeroString(Value))
+    // Truncate if we attempt to write too much.
+    StringRef S = Value.take_front(maxFieldLength() - 1);
+    if (auto EC = Writer->writeZeroString(S))
       return EC;
   } else {
     if (auto EC = Reader->readZeroString(Value))
@@ -124,6 +145,10 @@ Error CodeViewRecordIO::mapStringZ(StringRef &Value) {
 }
 
 Error CodeViewRecordIO::mapGuid(StringRef &Guid) {
+  constexpr uint32_t GuidSize = 16;
+  if (maxFieldLength() < GuidSize)
+    return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
   if (isWriting()) {
     assert(Guid.size() == 16 && "Invalid Guid Size!");
     if (auto EC = Writer->writeFixedString(Guid))
diff --git a/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp b/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp
deleted file mode 100644 (file)
index ac2ef39..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-//===-- FieldListRecordBuilder.cpp ----------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
-
-using namespace llvm;
-using namespace codeview;
-
-FieldListRecordBuilder::FieldListRecordBuilder()
-    : ListRecordBuilder(TypeRecordKind::FieldList) {}
-
-void FieldListRecordBuilder::writeMemberType(const BaseClassRecord &Record) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  Builder.writeTypeRecordKind(TypeRecordKind::BaseClass);
-  Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
-  Builder.writeTypeIndex(Record.getBaseType());
-  Builder.writeEncodedUnsignedInteger(Record.getBaseOffset());
-
-  finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const EnumeratorRecord &Record) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  Builder.writeTypeRecordKind(TypeRecordKind::Enumerator);
-  Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
-  // FIXME: Handle full APInt such as __int128.
-  Builder.writeEncodedUnsignedInteger(Record.getValue().getZExtValue());
-  Builder.writeNullTerminatedString(Record.getName());
-
-  finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const DataMemberRecord &Record) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  Builder.writeTypeRecordKind(Record.getKind());
-  Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
-  Builder.writeTypeIndex(Record.getType());
-  Builder.writeEncodedUnsignedInteger(Record.getFieldOffset());
-  Builder.writeNullTerminatedString(Record.getName());
-
-  finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(
-    const OverloadedMethodRecord &Record) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  Builder.writeTypeRecordKind(TypeRecordKind::OverloadedMethod);
-  Builder.writeUInt16(Record.getNumOverloads());
-  Builder.writeTypeIndex(Record.getMethodList());
-  Builder.writeNullTerminatedString(Record.getName());
-
-  finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const OneMethodRecord &Record) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  uint16_t Flags = static_cast<uint16_t>(Record.getAccess());
-  Flags |= static_cast<uint16_t>(Record.getKind()) << MethodKindShift;
-  Flags |= static_cast<uint16_t>(Record.getOptions());
-
-  Builder.writeTypeRecordKind(TypeRecordKind::OneMethod);
-  Builder.writeUInt16(Flags);
-  Builder.writeTypeIndex(Record.getType());
-  if (Record.isIntroducingVirtual()) {
-    assert(Record.getVFTableOffset() >= 0);
-    Builder.writeInt32(Record.getVFTableOffset());
-  } else {
-    assert(Record.getVFTableOffset() == -1);
-  }
-
-  Builder.writeNullTerminatedString(Record.getName());
-
-  finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const NestedTypeRecord &Record) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  Builder.writeTypeRecordKind(Record.getKind());
-  Builder.writeUInt16(0);
-  Builder.writeTypeIndex(Record.getNestedType());
-  Builder.writeNullTerminatedString(Record.getName());
-
-  finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(
-    const StaticDataMemberRecord &Record) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  Builder.writeTypeRecordKind(Record.getKind());
-  Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
-  Builder.writeTypeIndex(Record.getType());
-  Builder.writeNullTerminatedString(Record.getName());
-
-  finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(
-    const VirtualBaseClassRecord &Record) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  Builder.writeTypeRecordKind(Record.getKind());
-  Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
-  Builder.writeTypeIndex(Record.getBaseType());
-  Builder.writeTypeIndex(Record.getVBPtrType());
-  Builder.writeEncodedInteger(Record.getVBPtrOffset());
-  Builder.writeEncodedUnsignedInteger(Record.getVTableIndex());
-
-  finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const VFPtrRecord &Record) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  Builder.writeTypeRecordKind(TypeRecordKind::VFPtr);
-  Builder.writeUInt16(0);
-  Builder.writeTypeIndex(Record.getType());
-
-  finishSubRecord();
-}
diff --git a/lib/DebugInfo/CodeView/ListRecordBuilder.cpp b/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
deleted file mode 100644 (file)
index efac32a..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-//===-- ListRecordBuilder.cpp ---------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/SmallString.h"
-#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-
-using namespace llvm;
-using namespace codeview;
-
-ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
-    : Kind(Kind), Builder(Kind) {}
-
-void ListRecordBuilder::writeMemberType(const ListContinuationRecord &R) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  assert(getLastContinuationSize() < MaxRecordLength - 8 && "continuation won't fit");
-
-  Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
-  Builder.writeUInt16(0);
-  Builder.writeTypeIndex(R.getContinuationIndex());
-
-  // End the current segment manually so that nothing comes after the
-  // continuation.
-  ContinuationOffsets.push_back(Builder.size());
-  SubrecordStart = Builder.size();
-}
-
-void ListRecordBuilder::finishSubRecord() {
-  // The type table inserts a 16 bit size field before each list, so factor that
-  // into our alignment padding.
-  uint32_t Remainder =
-      (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4;
-  if (Remainder != 0) {
-    for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
-         --PaddingBytesLeft) {
-      Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft);
-    }
-  }
-
-  // Check if this subrecord makes the current segment not fit in 64K minus the
-  // space for a continuation record (8 bytes). If the segment does not fit,
-  // back up and insert a continuation record, sliding the current subrecord
-  // down.
-  if (getLastContinuationSize() > MaxRecordLength - 8) {
-    assert(SubrecordStart != 0 && "can't slide from the start!");
-    SmallString<128> SubrecordCopy(
-        Builder.str().slice(SubrecordStart, Builder.size()));
-    assert(SubrecordCopy.size() < MaxRecordLength - 8 &&
-           "subrecord is too large to slide!");
-    Builder.truncate(SubrecordStart);
-
-    // Write a placeholder continuation record.
-    Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
-    Builder.writeUInt16(0);
-    Builder.writeUInt32(0);
-    ContinuationOffsets.push_back(Builder.size());
-    assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size");
-    assert(getLastContinuationSize() < MaxRecordLength && "segment too big");
-
-    // Start a new list record of the appropriate kind, and copy the previous
-    // subrecord into place.
-    Builder.writeTypeRecordKind(Kind);
-    Builder.writeBytes(SubrecordCopy);
-  }
-
-  SubrecordStart = Builder.size();
-}
-
-TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) {
-  // Get the continuation segments as a reversed vector of StringRefs for
-  // convenience.
-  SmallVector<StringRef, 1> Segments;
-  StringRef Data = str();
-  size_t LastEnd = 0;
-  for (size_t SegEnd : ContinuationOffsets) {
-    Segments.push_back(Data.slice(LastEnd, SegEnd));
-    LastEnd = SegEnd;
-  }
-  Segments.push_back(Data.slice(LastEnd, Builder.size()));
-
-  // Pop the last record off and emit it directly.
-  StringRef LastRec = Segments.pop_back_val();
-  TypeIndex ContinuationIndex = Table.writeRecord(LastRec);
-
-  // Emit each record with a continuation in reverse order, so that each one
-  // references the previous record.
-  for (StringRef Rec : reverse(Segments)) {
-    assert(*reinterpret_cast<const ulittle16_t *>(Rec.data()) ==
-           unsigned(Kind));
-    ulittle32_t *ContinuationPtr =
-        reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1;
-    *ContinuationPtr = ContinuationIndex.getIndex();
-    ContinuationIndex = Table.writeRecord(Rec);
-  }
-  return ContinuationIndex;
-}
diff --git a/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp b/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp
deleted file mode 100644 (file)
index 8b9e73b..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-//===-- MemoryTypeTableBuilder.cpp ----------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-
-using namespace llvm;
-using namespace codeview;
-
-TypeIndex MemoryTypeTableBuilder::writeRecord(StringRef Data) {
-  assert(Data.size() <= UINT16_MAX);
-  auto I = HashedRecords.find(Data);
-  if (I != HashedRecords.end()) {
-    return I->second;
-  }
-
-  // The record provided by the user lacks the 2 byte size field prefix and is
-  // not padded to 4 bytes. Ultimately, that is what gets emitted in the object
-  // file, so pad it out now.
-  const int SizeOfRecLen = 2;
-  const int Align = 4;
-  int TotalSize = alignTo(Data.size() + SizeOfRecLen, Align);
-  assert(TotalSize - SizeOfRecLen <= UINT16_MAX);
-  char *Mem =
-      reinterpret_cast<char *>(RecordStorage.Allocate(TotalSize, Align));
-  *reinterpret_cast<ulittle16_t *>(Mem) = uint16_t(TotalSize - SizeOfRecLen);
-  memcpy(Mem + SizeOfRecLen, Data.data(), Data.size());
-  for (int I = Data.size() + SizeOfRecLen; I < TotalSize; ++I)
-    Mem[I] = LF_PAD0 + (TotalSize - I);
-
-  TypeIndex TI(static_cast<uint32_t>(Records.size()) +
-               TypeIndex::FirstNonSimpleIndex);
-
-  // Use only the data supplied by the user as a key to the hash table, so that
-  // future lookups will succeed.
-  HashedRecords.insert(std::make_pair(StringRef(Mem + SizeOfRecLen, Data.size()), TI));
-  Records.push_back(StringRef(Mem, TotalSize));
-
-  return TI;
-}
diff --git a/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp b/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp
deleted file mode 100644 (file)
index ae089a3..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-//===-- MethodListRecordBuilder.cpp ---------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
-
-using namespace llvm;
-using namespace codeview;
-
-MethodListRecordBuilder::MethodListRecordBuilder()
-    : ListRecordBuilder(TypeRecordKind::MethodOverloadList) {}
-
-void MethodListRecordBuilder::writeMethod(MemberAccess Access, MethodKind Kind,
-                                          MethodOptions Options, TypeIndex Type,
-                                          int32_t VTableSlotOffset) {
-  TypeRecordBuilder &Builder = getBuilder();
-
-  uint16_t Flags = static_cast<uint16_t>(Access);
-  Flags |= static_cast<uint16_t>(Kind) << MethodKindShift;
-  Flags |= static_cast<uint16_t>(Options);
-
-  Builder.writeUInt16(Flags);
-  Builder.writeUInt16(0);
-  Builder.writeTypeIndex(Type);
-  switch (Kind) {
-  case MethodKind::IntroducingVirtual:
-  case MethodKind::PureIntroducingVirtual:
-    assert(VTableSlotOffset >= 0);
-    Builder.writeInt32(VTableSlotOffset);
-    break;
-
-  default:
-    assert(VTableSlotOffset == -1);
-    break;
-  }
-
-  // TODO: Fail if too big?
-}
-
-void MethodListRecordBuilder::writeMethod(const MethodInfo &Method) {
-  writeMethod(Method.getAccess(), Method.getKind(), Method.getOptions(),
-              Method.getType(), Method.getVTableSlotOffset());
-}
index 84abad91c53797f2ab138376ac2e841769fa8bb8..4274d834076a6181ac42cb02da1804c4850539bf 100644 (file)
@@ -428,7 +428,7 @@ Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
                                      MethodOverloadListRecord &MethodList) {
   for (auto &M : MethodList.getMethods()) {
     ListScope S(*W, "Method");
-    printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions());
+    printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions());
     printTypeIndex("Type", M.getType());
     if (M.isIntroducingVirtual())
       W->printHex("VFTableOffset", M.getVFTableOffset());
@@ -607,7 +607,7 @@ Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
 
 Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
                                      OneMethodRecord &Method) {
-  MethodKind K = Method.getKind();
+  MethodKind K = Method.getMethodKind();
   printMemberAttributes(Method.getAccess(), K, Method.getOptions());
   printTypeIndex("Type", Method.getType());
   // If virtual, then read the vftable offset.
diff --git a/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp b/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
deleted file mode 100644 (file)
index f775bdd..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-//===-- TypeRecordBuilder.cpp ---------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
-
-using namespace llvm;
-using namespace codeview;
-
-TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind)
-    : Kind(Kind), Stream(Buffer), Writer(Stream) {
-  writeTypeRecordKind(Kind);
-}
-
-StringRef TypeRecordBuilder::str() {
-  return StringRef(Buffer.data(), Buffer.size());
-}
-
-void TypeRecordBuilder::writeUInt8(uint8_t Value) {
-  Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeInt16(int16_t Value) {
-  Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeUInt16(uint16_t Value) {
-  Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeInt32(int32_t Value) {
-  Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeUInt32(uint32_t Value) {
-  Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeInt64(int64_t Value) {
-  Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeUInt64(uint64_t Value) {
-  Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeEncodedInteger(int64_t Value) {
-  if (Value >= 0) {
-    writeEncodedUnsignedInteger(static_cast<uint64_t>(Value));
-  } else {
-    writeEncodedSignedInteger(Value);
-  }
-}
-
-void TypeRecordBuilder::writeEncodedSignedInteger(int64_t Value) {
-  if (Value >= std::numeric_limits<int8_t>::min() &&
-      Value <= std::numeric_limits<int8_t>::max()) {
-    writeUInt16(LF_CHAR);
-    writeInt16(static_cast<int8_t>(Value));
-  } else if (Value >= std::numeric_limits<int16_t>::min() &&
-             Value <= std::numeric_limits<int16_t>::max()) {
-    writeUInt16(LF_SHORT);
-    writeInt16(static_cast<int16_t>(Value));
-  } else if (Value >= std::numeric_limits<int32_t>::min() &&
-             Value <= std::numeric_limits<int32_t>::max()) {
-    writeUInt16(LF_LONG);
-    writeInt32(static_cast<int32_t>(Value));
-  } else {
-    writeUInt16(LF_QUADWORD);
-    writeInt64(Value);
-  }
-}
-
-void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) {
-  if (Value < LF_CHAR) {
-    writeUInt16(static_cast<uint16_t>(Value));
-  } else if (Value <= std::numeric_limits<uint16_t>::max()) {
-    writeUInt16(LF_USHORT);
-    writeUInt16(static_cast<uint16_t>(Value));
-  } else if (Value <= std::numeric_limits<uint32_t>::max()) {
-    writeUInt16(LF_ULONG);
-    writeUInt32(static_cast<uint32_t>(Value));
-  } else {
-    writeUInt16(LF_UQUADWORD);
-    writeUInt64(Value);
-  }
-}
-
-void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) {
-  // Usually the null terminated string comes last, so truncate it to avoid a
-  // record larger than MaxNameLength. Don't do this if this is a list record.
-  // Those have special handling to split the record.
-  unsigned MaxNameLength = MaxRecordLength;
-  if (Kind != TypeRecordKind::FieldList &&
-      Kind != TypeRecordKind::MethodOverloadList)
-    MaxNameLength = maxBytesRemaining();
-  assert(MaxNameLength > 0 && "need room for null terminator");
-  Value = Value.take_front(MaxNameLength - 1);
-  Stream.write(Value.data(), Value.size());
-  writeUInt8(0);
-}
-
-void TypeRecordBuilder::writeGuid(StringRef Guid) {
-  assert(Guid.size() == 16);
-  Stream.write(Guid.data(), 16);
-}
-
-void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) {
-  writeUInt32(TypeInd.getIndex());
-}
-
-void TypeRecordBuilder::writeTypeRecordKind(TypeRecordKind Kind) {
-  writeUInt16(static_cast<uint16_t>(Kind));
-}
index d85a643c6d258d63ed6e030e41ad612bea86dd9a..f260ddad3fd482b7d04c7d0fa35056bd54bba22e 100644 (file)
@@ -17,24 +17,6 @@ using namespace llvm::codeview;
     return EC;
 
 namespace {
-struct MapStringZ {
-  Error operator()(CodeViewRecordIO &IO, StringRef &S) const {
-    return IO.mapStringZ(S);
-  }
-};
-
-struct MapInteger {
-  template <typename T> Error operator()(CodeViewRecordIO &IO, T &N) const {
-    return IO.mapInteger(N);
-  }
-};
-
-struct MapEnum {
-  template <typename T> Error operator()(CodeViewRecordIO &IO, T &N) const {
-    return IO.mapEnum(N);
-  }
-};
-
 struct MapOneMethodRecord {
   explicit MapOneMethodRecord(bool IsFromOverloadList)
       : IsFromOverloadList(IsFromOverloadList) {}
@@ -64,35 +46,97 @@ private:
 
 static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
                                   StringRef &UniqueName, bool HasUniqueName) {
-  error(IO.mapStringZ(Name));
-  if (HasUniqueName)
-    error(IO.mapStringZ(UniqueName));
+  if (IO.isWriting()) {
+    // Try to be smart about what we write here.  We can't write anything too
+    // large, so if we're going to go over the limit, truncate both the name
+    // and unique name by the same amount.
+    uint32_t BytesLeft = IO.maxFieldLength();
+    if (HasUniqueName) {
+      uint32_t BytesNeeded = Name.size() + UniqueName.size() + 2;
+      StringRef N = Name;
+      StringRef U = UniqueName;
+      if (BytesNeeded > BytesLeft) {
+        uint32_t BytesToDrop = (BytesNeeded - BytesLeft);
+        uint32_t DropN = std::min(N.size(), BytesToDrop / 2);
+        uint32_t DropU = std::min(U.size(), BytesToDrop - DropN);
+
+        N = N.drop_back(DropN);
+        U = U.drop_back(DropU);
+      }
+
+      error(IO.mapStringZ(N));
+      error(IO.mapStringZ(U));
+    } else {
+      uint32_t BytesNeeded = Name.size() + 1;
+      StringRef N = Name;
+      if (BytesNeeded > BytesLeft) {
+        uint32_t BytesToDrop = std::min(N.size(), BytesToDrop);
+        N = N.drop_back(BytesToDrop);
+      }
+      error(IO.mapStringZ(N));
+    }
+  } else {
+    error(IO.mapStringZ(Name));
+    if (HasUniqueName)
+      error(IO.mapStringZ(UniqueName));
+  }
 
   return Error::success();
 }
 
 Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
-  error(IO.beginRecord(CVR.Type));
+  assert(!TypeKind.hasValue() && "Already in a type mapping!");
+  assert(!MemberKind.hasValue() && "Already in a member mapping!");
+
+  // FieldList and MethodList records can be any length because they can be
+  // split with continuation records.  All other record types cannot be
+  // longer than the maximum record length.
+  Optional<uint32_t> MaxLen;
+  if (CVR.Type != TypeLeafKind::LF_FIELDLIST &&
+      CVR.Type != TypeLeafKind::LF_METHODLIST)
+    MaxLen = MaxRecordLength - sizeof(RecordPrefix);
+  error(IO.beginRecord(MaxLen));
   TypeKind = CVR.Type;
   return Error::success();
 }
 
 Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
+  assert(TypeKind.hasValue() && "Not in a type mapping!");
+  assert(!MemberKind.hasValue() && "Still in a member mapping!");
+
   error(IO.endRecord());
+
   TypeKind.reset();
   return Error::success();
 }
 
 Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
+  assert(TypeKind.hasValue() && "Not in a type mapping!");
+  assert(!MemberKind.hasValue() && "Already in a member mapping!");
+
+  // The largest possible subrecord is one in which there is a record prefix,
+  // followed by the subrecord, followed by a continuation, and that entire
+  // sequence spaws `MaxRecordLength` bytes.  So the record's length is
+  // calculated as follows.
+  constexpr uint32_t ContinuationLength = 8;
+  error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
+                       ContinuationLength));
+
+  MemberKind = Record.Kind;
   return Error::success();
 }
 
 Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
+  assert(TypeKind.hasValue() && "Not in a type mapping!");
+  assert(MemberKind.hasValue() && "Not in a member mapping!");
+
   if (!IO.isWriting()) {
     if (auto EC = IO.skipPadding())
       return EC;
   }
 
+  MemberKind.reset();
+  error(IO.endRecord());
   return Error::success();
 }
 
@@ -129,7 +173,9 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
 }
 
 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
-  error(IO.mapVectorN<uint32_t>(Record.StringIndices, MapInteger()));
+  error(IO.mapVectorN<uint32_t>(
+      Record.StringIndices,
+      [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
 
   return Error::success();
 }
@@ -245,7 +291,9 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
       NamesLen += Name.size() + 1;
   }
   error(IO.mapInteger(NamesLen));
-  error(IO.mapVectorTail(Record.MethodNames, MapStringZ()));
+  error(IO.mapVectorTail(
+      Record.MethodNames,
+      [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); }));
 
   return Error::success();
 }
@@ -295,7 +343,9 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
 
 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
                                           BuildInfoRecord &Record) {
-  error(IO.mapVectorN<uint16_t>(Record.ArgIndices, MapInteger()));
+  error(IO.mapVectorN<uint16_t>(
+      Record.ArgIndices,
+      [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
 
   return Error::success();
 }
diff --git a/lib/DebugInfo/CodeView/TypeSerializer.cpp b/lib/DebugInfo/CodeView/TypeSerializer.cpp
new file mode 100644 (file)
index 0000000..f24fcff
--- /dev/null
@@ -0,0 +1,243 @@
+//===- TypeSerialzier.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
+
+#include "llvm/DebugInfo/MSF/StreamWriter.h"
+
+#include <string.h>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+bool TypeSerializer::isInFieldList() const {
+  return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST;
+}
+
+TypeIndex TypeSerializer::calcNextTypeIndex() const {
+  if (LastTypeIndex.isNoneType())
+    return TypeIndex(TypeIndex::FirstNonSimpleIndex);
+  else
+    return TypeIndex(LastTypeIndex.getIndex() + 1);
+}
+
+TypeIndex TypeSerializer::incrementTypeIndex() {
+  TypeIndex Previous = LastTypeIndex;
+  LastTypeIndex = calcNextTypeIndex();
+  return Previous;
+}
+
+MutableArrayRef<uint8_t> TypeSerializer::getCurrentSubRecordData() {
+  assert(isInFieldList());
+  return getCurrentRecordData().drop_front(CurrentSegment.length());
+}
+
+MutableArrayRef<uint8_t> TypeSerializer::getCurrentRecordData() {
+  return MutableArrayRef<uint8_t>(RecordBuffer).take_front(Writer.getOffset());
+}
+
+Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) {
+  RecordPrefix Prefix;
+  Prefix.RecordKind = Kind;
+  Prefix.RecordLen = 0;
+  if (auto EC = Writer.writeObject(Prefix))
+    return EC;
+  return Error::success();
+}
+
+TypeIndex
+TypeSerializer::insertRecordBytesPrivate(MutableArrayRef<uint8_t> Record) {
+  assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
+
+  StringRef S(reinterpret_cast<const char *>(Record.data()), Record.size());
+
+  TypeIndex NextTypeIndex = calcNextTypeIndex();
+  auto Result = HashedRecords.try_emplace(S, NextTypeIndex);
+  if (Result.second) {
+    LastTypeIndex = NextTypeIndex;
+    SeenRecords.push_back(Record);
+  }
+  return Result.first->getValue();
+}
+
+Expected<MutableArrayRef<uint8_t>>
+TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) {
+  uint32_t Align = Record.size() % 4;
+  if (Align == 0)
+    return Record;
+
+  int PaddingBytes = 4 - Align;
+  int N = PaddingBytes;
+  while (PaddingBytes > 0) {
+    uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
+    if (auto EC = Writer.writeInteger(Pad))
+      return std::move(EC);
+    --PaddingBytes;
+  }
+  return MutableArrayRef<uint8_t>(Record.data(), Record.size() + N);
+}
+
+TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage)
+    : RecordStorage(Storage), LastTypeIndex(),
+      RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer), Writer(Stream),
+      Mapping(Writer) {
+  // RecordBuffer needs to be able to hold enough data so that if we are 1
+  // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes,
+  // we won't overflow.
+}
+
+ArrayRef<MutableArrayRef<uint8_t>> TypeSerializer::records() const {
+  return SeenRecords;
+}
+
+TypeIndex TypeSerializer::getLastTypeIndex() const { return LastTypeIndex; }
+
+TypeIndex TypeSerializer::insertRecordBytes(MutableArrayRef<uint8_t> Record) {
+  assert(!TypeKind.hasValue() && "Already in a type mapping!");
+  assert(Writer.getOffset() == 0 && "Stream has data already!");
+
+  return insertRecordBytesPrivate(Record);
+}
+
+Error TypeSerializer::visitTypeBegin(CVType &Record) {
+  assert(!TypeKind.hasValue() && "Already in a type mapping!");
+  assert(Writer.getOffset() == 0 && "Stream has data already!");
+
+  if (auto EC = writeRecordPrefix(Record.kind()))
+    return EC;
+
+  TypeKind = Record.kind();
+  if (auto EC = Mapping.visitTypeBegin(Record))
+    return EC;
+
+  return Error::success();
+}
+
+Expected<TypeIndex> TypeSerializer::visitTypeEndGetIndex(CVType &Record) {
+  assert(TypeKind.hasValue() && "Not in a type mapping!");
+  if (auto EC = Mapping.visitTypeEnd(Record))
+    return std::move(EC);
+
+  // Update the record's length and fill out the CVType members to point to
+  // the stable memory holding the record's data.
+  auto ThisRecordData = getCurrentRecordData();
+  auto ExpectedData = addPadding(ThisRecordData);
+  if (!ExpectedData)
+    return ExpectedData.takeError();
+  ThisRecordData = *ExpectedData;
+
+  RecordPrefix *Prefix =
+      reinterpret_cast<RecordPrefix *>(ThisRecordData.data());
+  Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t);
+
+  uint8_t *Copy = RecordStorage.Allocate<uint8_t>(ThisRecordData.size());
+  ::memcpy(Copy, ThisRecordData.data(), ThisRecordData.size());
+  ThisRecordData = MutableArrayRef<uint8_t>(Copy, ThisRecordData.size());
+  Record = CVType(*TypeKind, ThisRecordData);
+  TypeIndex InsertedTypeIndex = insertRecordBytesPrivate(ThisRecordData);
+
+  // Write out each additional segment in reverse order, and update each
+  // record's continuation index to point to the previous one.
+  for (auto X : reverse(FieldListSegments)) {
+    auto CIBytes = X.take_back(sizeof(uint32_t));
+    support::ulittle32_t *CI =
+        reinterpret_cast<support::ulittle32_t *>(CIBytes.data());
+    assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder");
+    *CI = InsertedTypeIndex.getIndex();
+    InsertedTypeIndex = insertRecordBytesPrivate(X);
+  }
+
+  TypeKind.reset();
+  Writer.setOffset(0);
+  FieldListSegments.clear();
+  CurrentSegment.SubRecords.clear();
+
+  return InsertedTypeIndex;
+}
+
+Error TypeSerializer::visitTypeEnd(CVType &Record) {
+  auto ExpectedIndex = visitTypeEndGetIndex(Record);
+  if (!ExpectedIndex)
+    return ExpectedIndex.takeError();
+  return Error::success();
+}
+
+Error TypeSerializer::visitMemberBegin(CVMemberRecord &Record) {
+  assert(isInFieldList() && "Not in a field list!");
+  assert(!MemberKind.hasValue() && "Already in a member record!");
+  MemberKind = Record.Kind;
+
+  if (auto EC = Mapping.visitMemberBegin(Record))
+    return EC;
+
+  return Error::success();
+}
+
+Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) {
+  if (auto EC = Mapping.visitMemberEnd(Record))
+    return EC;
+
+  // Check if this subrecord makes the current segment not fit in 64K minus
+  // the space for a continuation record (8 bytes). If the segment does not
+  // fit, insert a continuation record.
+  if (Writer.getOffset() > MaxRecordLength - ContinuationLength) {
+    MutableArrayRef<uint8_t> Data = getCurrentRecordData();
+    SubRecord LastSubRecord = CurrentSegment.SubRecords.back();
+    uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size;
+    auto CopyData = Data.take_front(CopySize);
+    auto LeftOverData = Data.drop_front(CopySize);
+    assert(LastSubRecord.Size == LeftOverData.size());
+
+    // Allocate stable storage for the record and copy the old record plus
+    // continuation over.
+    uint16_t LengthWithSize = CopySize + ContinuationLength;
+    assert(LengthWithSize <= MaxRecordLength);
+    RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(CopyData.data());
+    Prefix->RecordLen = LengthWithSize - sizeof(uint16_t);
+
+    uint8_t *SegmentBytes = RecordStorage.Allocate<uint8_t>(LengthWithSize);
+    auto SavedSegment = MutableArrayRef<uint8_t>(SegmentBytes, LengthWithSize);
+    msf::MutableByteStream CS(SavedSegment);
+    msf::StreamWriter CW(CS);
+    if (auto EC = CW.writeBytes(CopyData))
+      return EC;
+    if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX))
+      return EC;
+    if (auto EC = CW.writeInteger(uint16_t(0)))
+      return EC;
+    if (auto EC = CW.writeInteger(uint32_t(0xB0C0B0C0)))
+      return EC;
+    FieldListSegments.push_back(SavedSegment);
+
+    // Write a new placeholder record prefix to mark the start of this new
+    // top-level record.
+    Writer.setOffset(0);
+    if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST))
+      return EC;
+
+    // Then move over the subrecord that overflowed the old segment to the
+    // beginning of this segment.  Note that we have to use memmove here
+    // instead of Writer.writeBytes(), because the new and old locations
+    // could overlap.
+    ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(),
+              LeftOverData.size());
+    // And point the segment writer at the end of that subrecord.
+    Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix));
+
+    CurrentSegment.SubRecords.clear();
+    CurrentSegment.SubRecords.push_back(LastSubRecord);
+  }
+
+  // Update the CVMemberRecord since we may have shifted around or gotten
+  // padded.
+  Record.Data = getCurrentSubRecordData();
+
+  MemberKind.reset();
+  return Error::success();
+}
index 551a98a67c8fdba4fad4511f80d023f09f4b268f..ed6cf5743a1255d1e4abb854f05b3af533796703 100644 (file)
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
 #include "llvm/Support/Error.h"
@@ -54,7 +54,8 @@ namespace {
 ///   existing destination type index.
 class TypeStreamMerger : public TypeVisitorCallbacks {
 public:
-  TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) {
+  TypeStreamMerger(TypeTableBuilder &DestStream)
+      : DestStream(DestStream), FieldListBuilder(DestStream) {
     assert(!hadError());
   }
 
@@ -94,7 +95,7 @@ private:
   template <typename RecordType>
   Error visitKnownMemberRecordImpl(RecordType &Record) {
     FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);
-    FieldBuilder.writeMemberType(Record);
+    FieldListBuilder.writeMemberType(Record);
     return Error::success();
   }
 
@@ -102,9 +103,10 @@ private:
 
   bool FoundBadTypeIndex = false;
 
-  FieldListRecordBuilder FieldBuilder;
+  BumpPtrAllocator Allocator;
 
   TypeTableBuilder &DestStream;
+  FieldListRecordBuilder FieldListBuilder;
 
   bool IsInFieldList{false};
   size_t BeginIndexMapSize = 0;
@@ -120,6 +122,7 @@ Error TypeStreamMerger::visitTypeBegin(CVRecord<TypeLeafKind> &Rec) {
   if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
     assert(!IsInFieldList);
     IsInFieldList = true;
+    FieldListBuilder.begin();
   } else
     BeginIndexMapSize = IndexMap.size();
   return Error::success();
@@ -127,8 +130,8 @@ Error TypeStreamMerger::visitTypeBegin(CVRecord<TypeLeafKind> &Rec) {
 
 Error TypeStreamMerger::visitTypeEnd(CVRecord<TypeLeafKind> &Rec) {
   if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
-    IndexMap.push_back(DestStream.writeFieldList(FieldBuilder));
-    FieldBuilder.reset();
+    TypeIndex Index = FieldListBuilder.end();
+    IndexMap.push_back(Index);
     IsInFieldList = false;
   }
   return Error::success();
diff --git a/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
deleted file mode 100644 (file)
index 1bd0b3f..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-//===-- TypeTableBuilder.cpp ----------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-using namespace codeview;
-
-TypeTableBuilder::TypeTableBuilder() {}
-
-TypeTableBuilder::~TypeTableBuilder() {}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ModifierRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-
-  Builder.writeTypeIndex(Record.getModifiedType());
-  Builder.writeUInt16(static_cast<uint16_t>(Record.getModifiers()));
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ProcedureRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-
-  Builder.writeTypeIndex(Record.getReturnType());
-  Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
-  Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
-  Builder.writeUInt16(Record.getParameterCount());
-  Builder.writeTypeIndex(Record.getArgumentList());
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const MemberFunctionRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-
-  Builder.writeTypeIndex(Record.getReturnType());
-  Builder.writeTypeIndex(Record.getClassType());
-  Builder.writeTypeIndex(Record.getThisType());
-  Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
-  Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
-  Builder.writeUInt16(Record.getParameterCount());
-  Builder.writeTypeIndex(Record.getArgumentList());
-  Builder.writeInt32(Record.getThisPointerAdjustment());
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ArgListRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-
-  Builder.writeUInt32(Record.getIndices().size());
-  for (TypeIndex TI : Record.getIndices()) {
-    Builder.writeTypeIndex(TI);
-  }
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const PointerRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-
-  Builder.writeTypeIndex(Record.getReferentType());
-  Builder.writeUInt32(Record.Attrs);
-
-  if (Record.isPointerToMember()) {
-    const MemberPointerInfo &M = Record.getMemberInfo();
-    Builder.writeTypeIndex(M.getContainingType());
-    Builder.writeUInt16(static_cast<uint16_t>(M.getRepresentation()));
-  }
-
-  return writeRecord(Builder);
-}
-
-static void writeNameAndUniqueName(TypeRecordBuilder &Builder, ClassOptions CO,
-                                   StringRef Name, StringRef UniqueName) {
-  // Truncate the names to half the remaining record length.
-  unsigned MaxNameLength = Builder.maxBytesRemaining() / 2;
-  Name = Name.take_front(MaxNameLength - 1);
-  UniqueName = UniqueName.take_front(MaxNameLength - 1);
-
-  Builder.writeNullTerminatedString(Name);
-  if ((CO & ClassOptions::HasUniqueName) != ClassOptions::None) {
-    Builder.writeNullTerminatedString(UniqueName);
-  }
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ArrayRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-
-  Builder.writeTypeIndex(Record.getElementType());
-  Builder.writeTypeIndex(Record.getIndexType());
-  Builder.writeEncodedUnsignedInteger(Record.getSize());
-  Builder.writeNullTerminatedString(Record.getName());
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ClassRecord &Record) {
-  assert((Record.getKind() == TypeRecordKind::Struct) ||
-         (Record.getKind() == TypeRecordKind::Class) ||
-         (Record.getKind() == TypeRecordKind::Interface));
-
-  TypeRecordBuilder Builder(Record.getKind());
-
-  Builder.writeUInt16(Record.getMemberCount());
-  uint16_t Flags =
-      static_cast<uint16_t>(Record.getOptions()) |
-      (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift) |
-      (static_cast<uint16_t>(Record.getWinRTKind())
-       << ClassRecord::WinRTKindShift);
-  Builder.writeUInt16(Flags);
-  Builder.writeTypeIndex(Record.getFieldList());
-  Builder.writeTypeIndex(Record.getDerivationList());
-  Builder.writeTypeIndex(Record.getVTableShape());
-  Builder.writeEncodedUnsignedInteger(Record.getSize());
-  writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(),
-                         Record.getUniqueName());
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const UnionRecord &Record) {
-  TypeRecordBuilder Builder(TypeRecordKind::Union);
-  Builder.writeUInt16(Record.getMemberCount());
-  uint16_t Flags =
-      static_cast<uint16_t>(Record.getOptions()) |
-      (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift);
-  Builder.writeUInt16(Flags);
-  Builder.writeTypeIndex(Record.getFieldList());
-  Builder.writeEncodedUnsignedInteger(Record.getSize());
-  writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(),
-                         Record.getUniqueName());
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const EnumRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-
-  Builder.writeUInt16(Record.getMemberCount());
-  Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
-  Builder.writeTypeIndex(Record.getUnderlyingType());
-  Builder.writeTypeIndex(Record.getFieldList());
-  writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(),
-                         Record.getUniqueName());
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const BitFieldRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-
-  Builder.writeTypeIndex(Record.getType());
-  Builder.writeUInt8(Record.getBitSize());
-  Builder.writeUInt8(Record.getBitOffset());
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const VFTableShapeRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-
-  ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
-
-  Builder.writeUInt16(Slots.size());
-  for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
-    uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
-    if ((SlotIndex + 1) < Slots.size()) {
-      Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
-    }
-    Builder.writeUInt8(Byte);
-  }
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const VFTableRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-  Builder.writeTypeIndex(Record.getCompleteClass());
-  Builder.writeTypeIndex(Record.getOverriddenVTable());
-  Builder.writeUInt32(Record.getVFPtrOffset());
-
-  // Sum up the lengths of the null-terminated names.
-  size_t NamesLen = Record.getName().size() + 1;
-  for (StringRef MethodName : Record.getMethodNames())
-    NamesLen += MethodName.size() + 1;
-
-  // FIXME: Avoid creating a record longer than MaxRecordLength.
-  Builder.writeUInt32(NamesLen);
-  Builder.writeNullTerminatedString(Record.getName());
-  for (StringRef MethodName : Record.getMethodNames())
-    Builder.writeNullTerminatedString(MethodName);
-
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const StringIdRecord &Record) {
-  TypeRecordBuilder Builder(TypeRecordKind::StringId);
-  Builder.writeTypeIndex(Record.getId());
-  Builder.writeNullTerminatedString(Record.getString());
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const UdtSourceLineRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-  Builder.writeTypeIndex(Record.getUDT());
-  Builder.writeTypeIndex(Record.getSourceFile());
-  Builder.writeUInt32(Record.getLineNumber());
-  return writeRecord(Builder);
-}
-
-TypeIndex
-TypeTableBuilder::writeKnownType(const UdtModSourceLineRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-  Builder.writeTypeIndex(Record.getUDT());
-  Builder.writeTypeIndex(Record.getSourceFile());
-  Builder.writeUInt32(Record.getLineNumber());
-  Builder.writeUInt16(Record.getModule());
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const FuncIdRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-  Builder.writeTypeIndex(Record.getParentScope());
-  Builder.writeTypeIndex(Record.getFunctionType());
-  Builder.writeNullTerminatedString(Record.getName());
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const MemberFuncIdRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-  Builder.writeTypeIndex(Record.getClassType());
-  Builder.writeTypeIndex(Record.getFunctionType());
-  Builder.writeNullTerminatedString(Record.getName());
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const BuildInfoRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-  assert(Record.getArgs().size() <= UINT16_MAX);
-  Builder.writeUInt16(Record.getArgs().size());
-  for (TypeIndex Arg : Record.getArgs())
-    Builder.writeTypeIndex(Arg);
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
-  TypeIndex I = writeRecord(Builder.str());
-  RecordKinds.push_back(Builder.kind());
-  return I;
-}
-
-TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {
-  TypeIndex I = FieldList.writeListRecord(*this);
-  RecordKinds.push_back(TypeRecordKind::FieldList);
-  return I;
-}
-
-TypeIndex
-TypeTableBuilder::writeKnownType(const MethodOverloadListRecord &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-  for (const OneMethodRecord &Method : Record.getMethods()) {
-    uint16_t Flags = static_cast<uint16_t>(Method.getAccess());
-    Flags |= static_cast<uint16_t>(Method.getKind())
-             << MemberAttributes::MethodKindShift;
-    Flags |= static_cast<uint16_t>(Method.getOptions());
-    Builder.writeUInt16(Flags);
-    Builder.writeUInt16(0); // padding
-    Builder.writeTypeIndex(Method.getType());
-    if (Method.isIntroducingVirtual()) {
-      assert(Method.getVFTableOffset() >= 0);
-      Builder.writeInt32(Method.getVFTableOffset());
-    } else {
-      assert(Method.getVFTableOffset() == -1);
-    }
-  }
-
-  // TODO: Split the list into multiple records if it's longer than 64KB, using
-  // a subrecord of TypeRecordKind::Index to chain the records together.
-  return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const TypeServer2Record &Record) {
-  TypeRecordBuilder Builder(Record.getKind());
-  Builder.writeGuid(Record.getGuid());
-  Builder.writeUInt32(Record.getAge());
-  Builder.writeNullTerminatedString(Record.getName());
-  return writeRecord(Builder);
-}
index 3d0e8237609aa2ae658d4524c375ddfaca93fd40..736b5094defca527d675249676d35560e72216b7 100644 (file)
@@ -18,7 +18,7 @@
 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
-#include "llvm/DebugInfo/CodeView/TypeSerializationVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/PDB/PDBExtras.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
@@ -244,8 +244,7 @@ void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>::
             pdb::yaml::SerializationContext &Context) {
   codeview::TypeVisitorCallbackPipeline Pipeline;
   codeview::TypeDeserializer Deserializer;
-  codeview::TypeSerializationVisitor Serializer(Context.FieldListBuilder,
-                                                Context.TypeTableBuilder);
+  codeview::TypeSerializer Serializer(Context.Allocator);
   pdb::TpiHashUpdater Hasher;
 
   if (IO.outputting()) {
@@ -255,6 +254,11 @@ void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>::
   } else {
     // For Yaml to PDB, extract from the high level record type, then write it
     // to bytes.
+
+    // This might be interpreted as a hack, but serializing FieldList
+    // sub-records requires having access to the same serializer being used by
+    // the FieldList itself.
+    Context.ActiveSerializer = &Serializer;
     Pipeline.addCallbackToPipeline(Context.Dumper);
     Pipeline.addCallbackToPipeline(Serializer);
     Pipeline.addCallbackToPipeline(Hasher);
@@ -262,4 +266,5 @@ void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>::
 
   codeview::CVTypeVisitor Visitor(Pipeline);
   consumeError(Visitor.visitTypeRecord(Obj.Record));
+  Context.ActiveSerializer = nullptr;
 }
index 3456b15f8ded696d86e7ef050a84e836479eeebb..dcf29d249d601f91c0ea0ece2786c95ec0f24a7f 100644 (file)
 
 #include "PdbYaml.h"
 #include "YamlTypeDumper.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
+#include "llvm/Support/Allocator.h"
 
 namespace llvm {
+namespace codeview {
+class TypeSerializer;
+}
 namespace yaml {
 class IO;
 }
@@ -24,10 +26,11 @@ namespace pdb {
 namespace yaml {
 struct SerializationContext {
   explicit SerializationContext(llvm::yaml::IO &IO, BumpPtrAllocator &Allocator)
-      : Dumper(IO, *this), TypeTableBuilder(Allocator) {}
+      : Dumper(IO, *this), Allocator(Allocator) {}
+
   codeview::yaml::YamlTypeDumperCallbacks Dumper;
-  codeview::MemoryTypeTableBuilder TypeTableBuilder;
-  codeview::FieldListRecordBuilder FieldListBuilder;
+  BumpPtrAllocator &Allocator;
+  codeview::TypeSerializer *ActiveSerializer = nullptr;
 };
 }
 }
index 8fde16be1bc71400fe1c7450206638c19387e777..5c527c71c7e44a74cab0e95790af883ce47ee787 100644 (file)
@@ -15,7 +15,7 @@
 #include "llvm/DebugInfo/CodeView/EnumTables.h"
 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeSerializationVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/PDB/Raw/TpiHashing.h"
 
@@ -540,15 +540,27 @@ void llvm::codeview::yaml::YamlTypeDumperCallbacks::visitKnownRecordImpl(
     // which will recurse back to the standard handler for top-level fields
     // (top-level and member fields all have the exact same Yaml syntax so use
     // the same parser).
-    //
-    // If we are not outputting, then the array contains no data starting out,
-    // and is instead populated from the sequence represented by the yaml --
-    // again, using the same logic that we use for top-level records.
     FieldListRecordSplitter Splitter(FieldListRecords);
     CVTypeVisitor V(Splitter);
     consumeError(V.visitFieldListMemberStream(FieldList.Data));
+    YamlIO.mapRequired("FieldList", FieldListRecords, Context);
+  } else {
+    // If we are not outputting, then the array contains no data starting out,
+    // and is instead populated from the sequence represented by the yaml --
+    // again, using the same logic that we use for top-level records.
+    assert(Context.ActiveSerializer && "There is no active serializer!");
+    codeview::TypeVisitorCallbackPipeline Pipeline;
+    pdb::TpiHashUpdater Hasher;
+
+    // For Yaml to PDB, dump it (to fill out the record fields from the Yaml)
+    // then serialize those fields to bytes, then update their hashes.
+    Pipeline.addCallbackToPipeline(Context.Dumper);
+    Pipeline.addCallbackToPipeline(*Context.ActiveSerializer);
+    Pipeline.addCallbackToPipeline(Hasher);
+
+    codeview::CVTypeVisitor Visitor(Pipeline);
+    YamlIO.mapRequired("FieldList", FieldListRecords, Visitor);
   }
-  YamlIO.mapRequired("FieldList", FieldListRecords, Context);
 }
 
 namespace llvm {
@@ -558,31 +570,30 @@ struct MappingContextTraits<pdb::yaml::PdbTpiFieldListRecord,
                             pdb::yaml::SerializationContext> {
   static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
                       pdb::yaml::SerializationContext &Context) {
+    assert(IO.outputting());
     codeview::TypeVisitorCallbackPipeline Pipeline;
 
     msf::ByteStream Data(Obj.Record.Data);
     msf::StreamReader FieldReader(Data);
     codeview::FieldListDeserializer Deserializer(FieldReader);
-    codeview::TypeSerializationVisitor Serializer(Context.FieldListBuilder,
-                                                  Context.TypeTableBuilder);
-    pdb::TpiHashUpdater Hasher;
 
-    if (IO.outputting()) {
-      // For PDB to Yaml, deserialize into a high level record type, then dump
-      // it.
-      Pipeline.addCallbackToPipeline(Deserializer);
-      Pipeline.addCallbackToPipeline(Context.Dumper);
-    } else {
-      // For Yaml to PDB, extract from the high level record type, then write it
-      // to bytes.
-      Pipeline.addCallbackToPipeline(Context.Dumper);
-      Pipeline.addCallbackToPipeline(Serializer);
-      Pipeline.addCallbackToPipeline(Hasher);
-    }
+    // For PDB to Yaml, deserialize into a high level record type, then dump
+    // it.
+    Pipeline.addCallbackToPipeline(Deserializer);
+    Pipeline.addCallbackToPipeline(Context.Dumper);
 
     codeview::CVTypeVisitor Visitor(Pipeline);
     consumeError(Visitor.visitMemberRecord(Obj.Record));
   }
 };
+
+template <>
+struct MappingContextTraits<pdb::yaml::PdbTpiFieldListRecord,
+                            codeview::CVTypeVisitor> {
+  static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
+                      codeview::CVTypeVisitor &Visitor) {
+    consumeError(Visitor.visitMemberRecord(Obj.Record));
+  }
+};
 }
 }
index 75b37b041f0f8e3216730e76c8329f87b4aca927..3f15ba0bf85d5ecd9a6ca3e9dc00552318242d43 100644 (file)
@@ -11,7 +11,6 @@
 #define LLVM_TOOLS_LLVMPDBDUMP_YAMLTYPEDUMPER_H
 
 #include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
 #include "llvm/Support/YAMLTraits.h"
 
index 73118eb7cd0744379f1087231c8c4b907e5a3931..0ca186519cd24290db474bcf12f67c6cb68fcbae 100644 (file)
@@ -24,7 +24,6 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/CodeView/Line.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
 #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
@@ -34,6 +33,7 @@
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
 #include "llvm/DebugInfo/MSF/ByteStream.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Object/ObjectFile.h"
@@ -79,8 +79,7 @@ public:
   void printCOFFBaseReloc() override;
   void printCOFFDebugDirectory() override;
   void printCodeViewDebugInfo() override;
-  void
-  mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) override;
+  void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) override;
   void printStackMap() const override;
 private:
   void printSymbol(const SymbolRef &Sym);
@@ -1063,7 +1062,7 @@ void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
   W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset);
 }
 
-void COFFDumper::mergeCodeViewTypes(MemoryTypeTableBuilder &CVTypes) {
+void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVTypes) {
   for (const SectionRef &S : Obj->sections()) {
     StringRef SectionName;
     error(S.getName(SectionName));
@@ -1545,12 +1544,12 @@ void COFFDumper::printStackMap() const {
                         StackMapV2Parser<support::big>(StackMapContentsArray));
 }
 
-void llvm::dumpCodeViewMergedTypes(
-    ScopedPrinter &Writer, llvm::codeview::MemoryTypeTableBuilder &CVTypes) {
+void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
+                                   llvm::codeview::TypeTableBuilder &CVTypes) {
   // Flatten it first, then run our dumper on it.
   ListScope S(Writer, "MergedTypeStream");
   SmallString<0> Buf;
-  CVTypes.ForEachRecord([&](TypeIndex TI, StringRef Record) {
+  CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
     Buf.append(Record.begin(), Record.end());
   });
   CVTypeDumper CVTD(&Writer, opts::CodeViewSubsectionBytes);
index 9368cc562fe0e2f2f1841629d475b3425443ed9f..e3b65038aebe6b8b3d78288dd985e428410ec84e 100644 (file)
@@ -19,7 +19,7 @@ class COFFImportFile;
 class ObjectFile;
 }
 namespace codeview {
-class MemoryTypeTableBuilder;
+class TypeTableBuilder;
 }
 
 class ScopedPrinter;
@@ -65,8 +65,7 @@ public:
   virtual void printCOFFBaseReloc() { }
   virtual void printCOFFDebugDirectory() { }
   virtual void printCodeViewDebugInfo() { }
-  virtual void
-  mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) {}
+  virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) {}
 
   // Only implemented for MachO.
   virtual void printMachODataInCode() { }
@@ -97,7 +96,7 @@ std::error_code createMachODumper(const object::ObjectFile *Obj,
 void dumpCOFFImportFile(const object::COFFImportFile *File);
 
 void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
-                             llvm::codeview::MemoryTypeTableBuilder &CVTypes);
+                             llvm::codeview::TypeTableBuilder &CVTypes);
 
 } // namespace llvm
 
index caf44311a9c47ee90a41894961f049a33aab0a99..ede1f0712bddaaaa57280edd10e6246c75683641 100644 (file)
@@ -22,7 +22,7 @@
 #include "llvm-readobj.h"
 #include "Error.h"
 #include "ObjDumper.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/COFFImportFile.h"
 #include "llvm/Object/ELFObjectFile.h"
@@ -332,14 +332,14 @@ static bool isMipsArch(unsigned Arch) {
   }
 }
 namespace {
-struct TypeTableBuilder {
-  TypeTableBuilder() : Allocator(), Builder(Allocator) {}
+struct ReadObjTypeTableBuilder {
+  ReadObjTypeTableBuilder() : Allocator(), Builder(Allocator) {}
 
   llvm::BumpPtrAllocator Allocator;
-  llvm::codeview::MemoryTypeTableBuilder Builder;
+  llvm::codeview::TypeTableBuilder Builder;
 };
 }
-static TypeTableBuilder CVTypes;
+static ReadObjTypeTableBuilder CVTypes;
 
 /// @brief Creates an format-specific object file dumper.
 static std::error_code createDumper(const ObjectFile *Obj,