]> granicus.if.org Git - clang/commitdiff
Store unique IDs for identifiers in the PCH file. Use some bitmangling
authorDouglas Gregor <dgregor@apple.com>
Sat, 11 Apr 2009 00:14:32 +0000 (00:14 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 11 Apr 2009 00:14:32 +0000 (00:14 +0000)
so that we only need to perform the lookup and identifier resolution
once per identifier in the PCH file.

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

include/clang/Frontend/PCHBitCodes.h
include/clang/Frontend/PCHReader.h
include/clang/Frontend/PCHWriter.h
lib/Frontend/PCHReader.cpp
lib/Frontend/PCHWriter.cpp

index f60f65dfe7302a90ef585366e66db0f31e91f3be..eb7d47070416649da31e37feabb0e0e88b06991d 100644 (file)
@@ -41,6 +41,10 @@ namespace clang {
     /// other types that have serialized representations.
     typedef uint32_t TypeID;
 
+    /// \brief An ID number that refers to an identifier in a PCH
+    /// file.
+    typedef uint32_t IdentID;
+
     /// \brief Describes the various kinds of blocks that occur within
     /// a PCH file.
     enum BlockIDs {
@@ -104,7 +108,29 @@ namespace clang {
 
       /// \brief Record code for the target triple used to build the
       /// PCH file.
-      TARGET_TRIPLE = 4
+      TARGET_TRIPLE = 4,
+
+      /// \brief Record code for the table of offsets of each
+      /// identifier ID.
+      ///
+      /// The offset table contains offsets into the blob stored in
+      /// the IDENTIFIER_TABLE record. Each offset points to the
+      /// NULL-terminated string that corresponds to that identifier.
+      IDENTIFIER_OFFSET = 5,
+
+      /// \brief Record code for the identifier table.
+      ///
+      /// The identifier table is a simple blob that contains
+      /// NULL-terminated strings for all of the identifiers
+      /// referenced by the PCH file. The IDENTIFIER_OFFSET table
+      /// contains the mapping from identifier IDs to the characters
+      /// in this blob. Note that the starting offsets of all of the
+      /// identifiers are odd, so that, when the identifier offset
+      /// table is loaded in, we can use the low bit to distinguish
+      /// between offsets (for unresolved identifier IDs) and
+      /// IdentifierInfo pointers (for already-resolved identifier
+      /// IDs).
+      IDENTIFIER_TABLE = 6
     };
 
     /// \brief Record types used within a source manager block.
index 3efb3a55d68add7194a9239aba3026837a7720d7..c934b0e2d74c78fc00a5a7352d2ad392b16d09f0 100644 (file)
@@ -107,6 +107,17 @@ private:
   /// DeclContext.
   DeclContextOffsetsMap DeclContextOffsets;
 
+  /// \brief String data for the identifiers in the PCH file.
+  const char *IdentifierTable;
+
+  /// \brief String data for identifiers, indexed by the identifier ID
+  /// minus one.
+  ///
+  /// Each element in this array is either an offset into
+  /// IdentifierTable that contains the string data (if the lowest bit
+  /// is set) or is an IdentifierInfo* that has already been resolved.
+  llvm::SmallVector<uint64_t, 16> IdentifierData;
+
   PCHReadResult ReadPCHBlock();
   bool CheckPredefinesBuffer(const char *PCHPredef, 
                              unsigned PCHPredefLen,
index d1e2a715449d7ac4fd4f8b6c939b457266b6479b..92bab50db59ece6a0034a6277a59bf04458f93c0 100644 (file)
@@ -77,6 +77,14 @@ class PCHWriter {
   /// \brief The type ID that will be assigned to the next new type.
   pch::TypeID NextTypeID;
 
+  /// \brief Map that provides the ID numbers of each identifier in
+  /// the output stream.
+  ///
+  /// The ID numbers for identifiers are consecutive (in order of
+  /// discovery), starting at 1. An ID of zero refers to a NULL
+  /// IdentifierInfo.
+  llvm::DenseMap<const IdentifierInfo *, pch::IdentID> IdentifierIDs;
+
   void WriteTargetTriple(const TargetInfo &Target);
   void WriteLanguageOptions(const LangOptions &LangOpts);
   void WriteSourceManagerBlock(SourceManager &SourceMgr);
@@ -86,6 +94,7 @@ class PCHWriter {
   uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
   uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
   void WriteDeclsBlock(ASTContext &Context);
+  void WriteIdentifierTable();
 
 public:
   typedef llvm::SmallVector<uint64_t, 64> RecordData;
index 345e673b47193b981498bc34cb7b5d4bf2b47dca..b21beed307a2caba9821977ed47e5ada0d50546a 100644 (file)
@@ -477,7 +477,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCHBlock() {
         return IgnorePCH;
       break;
 
-    case pch::TARGET_TRIPLE:
+    case pch::TARGET_TRIPLE: {
       std::string TargetTriple(BlobStart, BlobLen);
       if (TargetTriple != Context.Target.getTargetTriple()) {
         Diag(diag::warn_pch_target_triple)
@@ -487,6 +487,27 @@ PCHReader::PCHReadResult PCHReader::ReadPCHBlock() {
       }
       break;
     }
+
+    case pch::IDENTIFIER_TABLE:
+      IdentifierTable = BlobStart;
+      break;
+
+    case pch::IDENTIFIER_OFFSET:
+      if (!IdentifierData.empty()) {
+        Error("Duplicate IDENTIFIER_OFFSET record in PCH file");
+        return Failure;
+      }
+      IdentifierData.swap(Record);
+#ifndef NDEBUG
+      for (unsigned I = 0, N = IdentifierData.size(); I != N; ++I) {
+        if ((IdentifierData[I] & 0x01) == 0) {
+          Error("Malformed identifier table in the precompiled header");
+          return Failure;
+        }
+      }
+#endif
+      break;
+    }
   }
 
   Error("Premature end of bitstream");
@@ -927,13 +948,22 @@ void PCHReader::PrintStats() {
 
 const IdentifierInfo *PCHReader::GetIdentifierInfo(const RecordData &Record, 
                                                    unsigned &Idx) {
-  // FIXME: we need unique IDs for identifiers.
-  std::string Str;
-  unsigned Length = Record[Idx++];
-  Str.resize(Length);
-  for (unsigned I = 0; I != Length; ++I)
-    Str[I] = Record[Idx++];
-  return &Context.Idents.get(Str);
+  pch::IdentID ID = Record[Idx++];
+  if (ID == 0)
+    return 0;
+
+  if (!IdentifierTable || IdentifierData.empty()) {
+    Error("No identifier table in PCH file");
+    return 0;
+  }
+
+  if (IdentifierData[ID - 1] & 0x01) {
+    uint64_t Offset = IdentifierData[ID - 1];
+    IdentifierData[ID - 1] = reinterpret_cast<uint64_t>(
+                               &Context.Idents.get(IdentifierTable + Offset));
+  }
+
+  return reinterpret_cast<const IdentifierInfo *>(IdentifierData[ID - 1]);
 }
 
 DeclarationName 
index 4963ea1160862ef8eb33a54418bc5463c53cfb96..3c795bf722a7921c346303714c92a891892ec6f1 100644 (file)
@@ -818,6 +818,55 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
   S.ExitBlock();
 }
 
+/// \brief Write the identifier table into the PCH file.
+///
+/// The identifier table consists of a blob containing string data
+/// (the actual identifiers themselves) and a separate "offsets" index
+/// that maps identifier IDs to locations within the blob.
+void PCHWriter::WriteIdentifierTable() {
+  using namespace llvm;
+
+  // Create and write out the blob that contains the identifier
+  // strings.
+  RecordData IdentOffsets;
+  IdentOffsets.resize(IdentifierIDs.size());
+  {
+    // Create the identifier string data.
+    std::vector<char> Data;
+    Data.push_back(0); // Data must not be empty.
+    for (llvm::DenseMap<const IdentifierInfo *, pch::IdentID>::iterator
+           ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();
+         ID != IDEnd; ++ID) {
+      assert(ID->first && "NULL identifier in identifier table");
+
+      // Make sure we're starting on an odd byte. The PCH reader
+      // expects the low bit to be set on all of the offsets.
+      if ((Data.size() & 0x01) == 0)
+        Data.push_back((char)0);
+
+      IdentOffsets[ID->second - 1] = Data.size();
+      Data.insert(Data.end(), 
+                  ID->first->getName(), 
+                  ID->first->getName() + ID->first->getLength());
+      Data.push_back((char)0);
+    }
+
+    // Create a blob abbreviation
+    BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+    Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_TABLE));
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Triple name
+    unsigned IDTableAbbrev = S.EmitAbbrev(Abbrev);
+
+    // Write the identifier table
+    RecordData Record;
+    Record.push_back(pch::IDENTIFIER_TABLE);
+    S.EmitRecordWithBlob(IDTableAbbrev, Record, &Data.front(), Data.size());
+  }
+
+  // Write the offsets table for identifier IDs.
+  S.EmitRecord(pch::IDENTIFIER_OFFSET, IdentOffsets);
+}
+
 PCHWriter::PCHWriter(llvm::BitstreamWriter &S) 
   : S(S), NextTypeID(pch::NUM_PREDEF_TYPE_IDS) { }
 
@@ -842,6 +891,7 @@ void PCHWriter::WritePCH(ASTContext &Context, const Preprocessor &PP) {
   WriteDeclsBlock(Context);
   S.EmitRecord(pch::TYPE_OFFSET, TypeOffsets);
   S.EmitRecord(pch::DECL_OFFSET, DeclOffsets);
+  WriteIdentifierTable();
   S.ExitBlock();
 }
 
@@ -858,11 +908,16 @@ void PCHWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) {
 }
 
 void PCHWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) {
-  // FIXME: Emit an identifier ID, not the actual string!
-  const char *Name = II->getName();
-  unsigned Len = strlen(Name);
-  Record.push_back(Len);
-  Record.insert(Record.end(), Name, Name + Len);
+  if (II == 0) {
+    Record.push_back(0);
+    return;
+  }
+
+  pch::IdentID &ID = IdentifierIDs[II];
+  if (ID == 0)
+    ID = IdentifierIDs.size();
+  
+  Record.push_back(ID);
 }
 
 void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {