2010-08-19 07:56:31 +08:00
|
|
|
//===--- ASTWriter.cpp - AST File Writer ----------------------------------===//
|
2009-04-10 06:27:44 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2010-08-19 07:56:21 +08:00
|
|
|
// This file defines the ASTWriter class, which writes AST files.
|
2009-04-10 06:27:44 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-08-19 07:56:37 +08:00
|
|
|
#include "clang/Serialization/ASTWriter.h"
|
2010-08-21 00:03:52 +08:00
|
|
|
#include "ASTCommon.h"
|
2010-08-13 04:07:10 +08:00
|
|
|
#include "clang/Sema/Sema.h"
|
|
|
|
#include "clang/Sema/IdentifierResolver.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/Decl.h"
|
|
|
|
#include "clang/AST/DeclContextInternals.h"
|
2010-08-25 13:32:35 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2010-10-25 01:26:40 +08:00
|
|
|
#include "clang/AST/DeclFriend.h"
|
2009-04-15 05:18:50 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
2010-08-24 15:32:53 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "clang/AST/Type.h"
|
2009-10-17 05:56:05 +08:00
|
|
|
#include "clang/AST/TypeLocVisitor.h"
|
2010-08-19 07:57:17 +08:00
|
|
|
#include "clang/Serialization/ASTReader.h"
|
2012-10-25 00:50:34 +08:00
|
|
|
#include "clang/Lex/HeaderSearchOptions.h"
|
2009-04-11 02:00:12 +08:00
|
|
|
#include "clang/Lex/MacroInfo.h"
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
#include "clang/Lex/PreprocessingRecord.h"
|
2009-04-11 02:00:12 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2009-04-25 04:03:17 +08:00
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
2009-04-10 11:52:48 +08:00
|
|
|
#include "clang/Basic/FileManager.h"
|
2010-11-24 03:19:34 +08:00
|
|
|
#include "clang/Basic/FileSystemStatCache.h"
|
2009-04-21 04:36:09 +08:00
|
|
|
#include "clang/Basic/OnDiskHashTable.h"
|
2009-04-10 11:52:48 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2009-04-14 00:31:14 +08:00
|
|
|
#include "clang/Basic/SourceManagerInternals.h"
|
2009-04-11 05:16:55 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2012-10-17 07:40:58 +08:00
|
|
|
#include "clang/Basic/TargetOptions.h"
|
2009-04-28 06:23:34 +08:00
|
|
|
#include "clang/Basic/Version.h"
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
#include "clang/Basic/VersionTuple.h"
|
2009-04-15 05:55:33 +08:00
|
|
|
#include "llvm/ADT/APFloat.h"
|
|
|
|
#include "llvm/ADT/APInt.h"
|
2009-10-18 07:52:28 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "llvm/Bitcode/BitstreamWriter.h"
|
2010-12-22 00:45:57 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2009-04-10 11:52:48 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2010-11-30 02:12:39 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
#include <algorithm>
|
2009-04-12 02:40:46 +08:00
|
|
|
#include <cstdio>
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
#include <string.h>
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
#include <utility>
|
2009-04-10 06:27:44 +08:00
|
|
|
using namespace clang;
|
2010-08-19 07:57:32 +08:00
|
|
|
using namespace clang::serialization;
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-07-31 01:03:48 +08:00
|
|
|
template <typename T, typename Allocator>
|
2011-07-23 18:55:15 +08:00
|
|
|
static StringRef data(const std::vector<T, Allocator> &v) {
|
|
|
|
if (v.empty()) return StringRef();
|
|
|
|
return StringRef(reinterpret_cast<const char*>(&v[0]),
|
2011-04-25 01:44:50 +08:00
|
|
|
sizeof(T) * v.size());
|
2010-07-31 01:03:48 +08:00
|
|
|
}
|
2011-04-25 01:44:50 +08:00
|
|
|
|
|
|
|
template <typename T>
|
2011-07-23 18:55:15 +08:00
|
|
|
static StringRef data(const SmallVectorImpl<T> &v) {
|
|
|
|
return StringRef(reinterpret_cast<const char*>(v.data()),
|
2011-04-25 01:44:50 +08:00
|
|
|
sizeof(T) * v.size());
|
2010-07-31 01:03:48 +08:00
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-04-27 14:16:06 +08:00
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
namespace {
|
2010-08-19 07:56:27 +08:00
|
|
|
class ASTTypeWriter {
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter &Writer;
|
2010-10-25 01:26:40 +08:00
|
|
|
ASTWriter::RecordDataImpl &Record;
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
/// \brief Type code that corresponds to the record generated.
|
2010-08-19 07:57:32 +08:00
|
|
|
TypeCode Code;
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record)
|
2010-08-19 07:57:32 +08:00
|
|
|
: Writer(Writer), Record(Record), Code(TYPE_EXT_QUAL) { }
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
void VisitArrayType(const ArrayType *T);
|
|
|
|
void VisitFunctionType(const FunctionType *T);
|
|
|
|
void VisitTagType(const TagType *T);
|
|
|
|
|
|
|
|
#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T);
|
|
|
|
#define ABSTRACT_TYPE(Class, Base)
|
|
|
|
#include "clang/AST/TypeNodes.def"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) {
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Built-in types are never serialized");
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitComplexType(const ComplexType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getElementType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_COMPLEX;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitPointerType(const PointerType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_POINTER;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_BLOCK_POINTER;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) {
|
2011-04-12 18:38:03 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record);
|
|
|
|
Record.push_back(T->isSpelledAsLValue());
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_LVALUE_REFERENCE;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
|
2011-04-12 18:38:03 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_RVALUE_REFERENCE;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitMemberPointerType(const MemberPointerType *T) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
|
|
|
Writer.AddTypeRef(QualType(T->getClass(), 0), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_MEMBER_POINTER;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitArrayType(const ArrayType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getElementType(), Record);
|
|
|
|
Record.push_back(T->getSizeModifier()); // FIXME: stable values
|
2009-09-25 03:53:00 +08:00
|
|
|
Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitArrayType(T);
|
|
|
|
Writer.AddAPInt(T->getSize(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_CONSTANT_ARRAY;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitArrayType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_INCOMPLETE_ARRAY;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitArrayType(T);
|
2009-07-06 23:59:29 +08:00
|
|
|
Writer.AddSourceLocation(T->getLBracketLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(T->getRBracketLoc(), Record);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(T->getSizeExpr());
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_VARIABLE_ARRAY;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitVectorType(const VectorType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getElementType(), Record);
|
|
|
|
Record.push_back(T->getNumElements());
|
2010-11-11 05:56:12 +08:00
|
|
|
Record.push_back(T->getVectorKind());
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_VECTOR;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitVectorType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_EXT_VECTOR;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getResultType(), Record);
|
2010-03-31 04:24:48 +08:00
|
|
|
FunctionType::ExtInfo C = T->getExtInfo();
|
|
|
|
Record.push_back(C.getNoReturn());
|
2011-04-09 16:18:08 +08:00
|
|
|
Record.push_back(C.getHasRegParm());
|
2010-03-31 06:15:11 +08:00
|
|
|
Record.push_back(C.getRegParm());
|
2010-01-19 01:14:39 +08:00
|
|
|
// FIXME: need to stabilize encoding of calling convention...
|
2010-03-31 04:24:48 +08:00
|
|
|
Record.push_back(C.getCC());
|
2011-06-16 07:02:42 +08:00
|
|
|
Record.push_back(C.getProducesResult());
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitFunctionType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_FUNCTION_NO_PROTO;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitFunctionType(T);
|
|
|
|
Record.push_back(T->getNumArgs());
|
|
|
|
for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I)
|
|
|
|
Writer.AddTypeRef(T->getArgType(I), Record);
|
|
|
|
Record.push_back(T->isVariadic());
|
2012-02-10 17:58:53 +08:00
|
|
|
Record.push_back(T->hasTrailingReturn());
|
2009-04-10 06:27:44 +08:00
|
|
|
Record.push_back(T->getTypeQuals());
|
2011-01-26 13:01:58 +08:00
|
|
|
Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
|
2011-03-12 19:50:43 +08:00
|
|
|
Record.push_back(T->getExceptionSpecType());
|
|
|
|
if (T->getExceptionSpecType() == EST_Dynamic) {
|
|
|
|
Record.push_back(T->getNumExceptions());
|
|
|
|
for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
|
|
|
|
Writer.AddTypeRef(T->getExceptionType(I), Record);
|
|
|
|
} else if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
|
|
|
|
Writer.AddStmt(T->getNoexceptExpr());
|
2012-04-22 01:47:47 +08:00
|
|
|
} else if (T->getExceptionSpecType() == EST_Uninstantiated) {
|
|
|
|
Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
|
|
|
|
Writer.AddDeclRef(T->getExceptionSpecTemplate(), Record);
|
Final piece of core issue 1330: delay computing the exception specification of
a defaulted special member function until the exception specification is needed
(using the same criteria used for the delayed instantiation of exception
specifications for function temploids).
EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like
EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to
resolve the exception specification.
This is enabled for all C++ modes: it's a little faster in the case where the
exception specification isn't used, allows our C++11-in-C++98 extensions to
work, and is still correct for C++98, since in that mode the computation of the
exception specification can't fail.
The diagnostics here aren't great (in particular, we should include implicit
evaluation of exception specifications for defaulted special members in the
template instantiation backtraces), but they're not much worse than before.
Our approach to the problem of cycles between in-class initializers and the
exception specification for a defaulted default constructor is modified a
little by this change -- we now reject any odr-use of a defaulted default
constructor if that constructor uses an in-class initializer and the use is in
an in-class initialzer which is declared lexically earlier. This is a closer
approximation to the current draft solution in core issue 1351, but isn't an
exact match (but the current draft wording isn't reasonable, so that's to be
expected).
llvm-svn: 160847
2012-07-27 12:22:15 +08:00
|
|
|
} else if (T->getExceptionSpecType() == EST_Unevaluated) {
|
|
|
|
Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
|
2011-03-12 19:50:43 +08:00
|
|
|
}
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_FUNCTION_PROTO;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
|
2009-12-05 06:46:56 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_UNRESOLVED_USING;
|
2009-12-05 06:46:56 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitTypedefType(const TypedefType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl(), Record);
|
2010-07-02 19:55:11 +08:00
|
|
|
assert(!T->isCanonicalUnqualified() && "Invalid typedef ?");
|
|
|
|
Writer.AddTypeRef(T->getCanonicalTypeInternal(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TYPEDEF;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) {
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(T->getUnderlyingExpr());
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TYPEOF_EXPR;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getUnderlyingType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TYPEOF;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
|
2012-02-13 02:42:33 +08:00
|
|
|
Writer.AddTypeRef(T->getUnderlyingType(), Record);
|
2009-06-25 03:06:50 +08:00
|
|
|
Writer.AddStmt(T->getUnderlyingExpr());
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_DECLTYPE;
|
2009-06-25 03:06:50 +08:00
|
|
|
}
|
|
|
|
|
2011-05-25 06:41:36 +08:00
|
|
|
void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {
|
|
|
|
Writer.AddTypeRef(T->getBaseType(), Record);
|
|
|
|
Writer.AddTypeRef(T->getUnderlyingType(), Record);
|
|
|
|
Record.push_back(T->getUTTKind());
|
|
|
|
Code = TYPE_UNARY_TRANSFORM;
|
|
|
|
}
|
|
|
|
|
2011-02-20 11:19:35 +08:00
|
|
|
void ASTTypeWriter::VisitAutoType(const AutoType *T) {
|
|
|
|
Writer.AddTypeRef(T->getDeducedType(), Record);
|
|
|
|
Code = TYPE_AUTO;
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitTagType(const TagType *T) {
|
2010-07-08 21:09:53 +08:00
|
|
|
Record.push_back(T->isDependentType());
|
2012-01-18 03:21:53 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(!T->isBeingDefined() &&
|
2009-04-10 06:27:44 +08:00
|
|
|
"Cannot serialize in the middle of a type definition");
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitRecordType(const RecordType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitTagType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_RECORD;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitEnumType(const EnumType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitTagType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_ENUM;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2011-01-06 09:58:22 +08:00
|
|
|
void ASTTypeWriter::VisitAttributedType(const AttributedType *T) {
|
|
|
|
Writer.AddTypeRef(T->getModifiedType(), Record);
|
|
|
|
Writer.AddTypeRef(T->getEquivalentType(), Record);
|
|
|
|
Record.push_back(T->getAttrKind());
|
|
|
|
Code = TYPE_ATTRIBUTED;
|
|
|
|
}
|
|
|
|
|
2009-10-18 17:09:24 +08:00
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitSubstTemplateTypeParmType(
|
2009-10-18 17:09:24 +08:00
|
|
|
const SubstTemplateTypeParmType *T) {
|
|
|
|
Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record);
|
|
|
|
Writer.AddTypeRef(T->getReplacementType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_SUBST_TEMPLATE_TYPE_PARM;
|
2009-10-18 17:09:24 +08:00
|
|
|
}
|
|
|
|
|
2011-01-14 10:55:32 +08:00
|
|
|
void
|
|
|
|
ASTTypeWriter::VisitSubstTemplateTypeParmPackType(
|
|
|
|
const SubstTemplateTypeParmPackType *T) {
|
|
|
|
Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record);
|
|
|
|
Writer.AddTemplateArgument(T->getArgumentPack(), Record);
|
|
|
|
Code = TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitTemplateSpecializationType(
|
2009-04-10 06:27:44 +08:00
|
|
|
const TemplateSpecializationType *T) {
|
2010-07-08 21:09:53 +08:00
|
|
|
Record.push_back(T->isDependentType());
|
2010-06-20 03:28:53 +08:00
|
|
|
Writer.AddTemplateName(T->getTemplateName(), Record);
|
|
|
|
Record.push_back(T->getNumArgs());
|
|
|
|
for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end();
|
|
|
|
ArgI != ArgE; ++ArgI)
|
|
|
|
Writer.AddTemplateArgument(*ArgI, Record);
|
2011-05-06 05:57:07 +08:00
|
|
|
Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() :
|
|
|
|
T->isCanonicalUnqualified() ? QualType()
|
2010-07-02 19:55:11 +08:00
|
|
|
: T->getCanonicalTypeInternal(),
|
|
|
|
Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TEMPLATE_SPECIALIZATION;
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
|
2010-06-30 16:49:25 +08:00
|
|
|
VisitArrayType(T);
|
|
|
|
Writer.AddStmt(T->getSizeExpr());
|
|
|
|
Writer.AddSourceRange(T->getBracketsRange(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_DEPENDENT_SIZED_ARRAY;
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitDependentSizedExtVectorType(
|
2010-06-20 03:28:53 +08:00
|
|
|
const DependentSizedExtVectorType *T) {
|
|
|
|
// FIXME: Serialize this type (C++ only)
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Cannot serialize dependent sized extended vector types");
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
|
2010-06-20 03:28:53 +08:00
|
|
|
Record.push_back(T->getDepth());
|
|
|
|
Record.push_back(T->getIndex());
|
|
|
|
Record.push_back(T->isParameterPack());
|
Re-applies the patch first applied way back in r106099, with
accompanying fixes to make it work today.
The core of this patch is to provide a link from a TemplateTypeParmType
back to the TemplateTypeParmDecl node which declared it. This in turn
provides much more precise information about the type, where it came
from, and how it functions for AST consumers.
To make the patch work almost a year after its first attempt, it needed
serialization support, and it now retains the old getName() interface.
Finally, it requires us to not attempt to instantiate the type in an
unsupported friend decl -- specifically those coming from template
friend decls but which refer to a specific type through a dependent
name.
A cleaner representation of the last item would be to build
FriendTemplateDecl nodes for these, storing their template parameters
etc, and to perform proper instantation of them like any other template
declaration. They can still be flagged as unsupported for the purpose of
access checking, etc.
This passed an asserts-enabled bootstrap for me, and the reduced test
case mentioned in the original review thread no longer causes issues,
likely fixed at somewhere amidst the 24k revisions that have elapsed.
llvm-svn: 130628
2011-05-01 08:51:33 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TEMPLATE_TYPE_PARM;
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitDependentNameType(const DependentNameType *T) {
|
2010-06-24 16:57:31 +08:00
|
|
|
Record.push_back(T->getKeyword());
|
|
|
|
Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
|
|
|
|
Writer.AddIdentifierRef(T->getIdentifier(), Record);
|
2010-07-02 19:55:24 +08:00
|
|
|
Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
|
|
|
|
: T->getCanonicalTypeInternal(),
|
|
|
|
Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_DEPENDENT_NAME;
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitDependentTemplateSpecializationType(
|
2010-06-20 03:28:53 +08:00
|
|
|
const DependentTemplateSpecializationType *T) {
|
2010-06-26 00:24:58 +08:00
|
|
|
Record.push_back(T->getKeyword());
|
|
|
|
Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
|
|
|
|
Writer.AddIdentifierRef(T->getIdentifier(), Record);
|
|
|
|
Record.push_back(T->getNumArgs());
|
|
|
|
for (DependentTemplateSpecializationType::iterator
|
|
|
|
I = T->begin(), E = T->end(); I != E; ++I)
|
|
|
|
Writer.AddTemplateArgument(*I, Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-12-20 10:24:11 +08:00
|
|
|
void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) {
|
|
|
|
Writer.AddTypeRef(T->getPattern(), Record);
|
2011-01-15 01:04:44 +08:00
|
|
|
if (llvm::Optional<unsigned> NumExpansions = T->getNumExpansions())
|
|
|
|
Record.push_back(*NumExpansions + 1);
|
|
|
|
else
|
|
|
|
Record.push_back(0);
|
2010-12-20 10:24:11 +08:00
|
|
|
Code = TYPE_PACK_EXPANSION;
|
|
|
|
}
|
|
|
|
|
2010-12-11 00:29:40 +08:00
|
|
|
void ASTTypeWriter::VisitParenType(const ParenType *T) {
|
|
|
|
Writer.AddTypeRef(T->getInnerType(), Record);
|
|
|
|
Code = TYPE_PAREN;
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
|
2010-05-12 05:36:43 +08:00
|
|
|
Record.push_back(T->getKeyword());
|
2010-06-26 00:24:58 +08:00
|
|
|
Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
|
|
|
|
Writer.AddTypeRef(T->getNamedType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_ELABORATED;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
|
2012-03-26 23:52:37 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
|
2010-04-27 08:57:59 +08:00
|
|
|
Writer.AddTypeRef(T->getInjectedSpecializationType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_INJECTED_CLASS_NAME;
|
2010-03-10 11:28:59 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
|
2012-01-18 03:21:53 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_OBJC_INTERFACE;
|
2010-05-15 19:32:37 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
|
2010-05-15 19:32:37 +08:00
|
|
|
Writer.AddTypeRef(T->getBaseType(), Record);
|
2009-04-10 06:27:44 +08:00
|
|
|
Record.push_back(T->getNumProtocols());
|
2010-05-15 19:32:37 +08:00
|
|
|
for (ObjCObjectType::qual_iterator I = T->qual_begin(),
|
2009-05-28 00:21:00 +08:00
|
|
|
E = T->qual_end(); I != E; ++I)
|
|
|
|
Writer.AddDeclRef(*I, Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_OBJC_OBJECT;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2009-06-18 06:40:22 +08:00
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_OBJC_OBJECT_POINTER;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2011-10-07 07:00:33 +08:00
|
|
|
void
|
|
|
|
ASTTypeWriter::VisitAtomicType(const AtomicType *T) {
|
|
|
|
Writer.AddTypeRef(T->getValueType(), Record);
|
|
|
|
Code = TYPE_ATOMIC;
|
|
|
|
}
|
|
|
|
|
2009-10-17 05:56:05 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter &Writer;
|
2010-10-25 01:26:40 +08:00
|
|
|
ASTWriter::RecordDataImpl &Record;
|
2009-10-17 05:56:05 +08:00
|
|
|
|
|
|
|
public:
|
2010-10-25 01:26:40 +08:00
|
|
|
TypeLocWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record)
|
2009-10-17 05:56:05 +08:00
|
|
|
: Writer(Writer), Record(Record) { }
|
|
|
|
|
2009-10-18 09:05:36 +08:00
|
|
|
#define ABSTRACT_TYPELOC(CLASS, PARENT)
|
2009-10-17 05:56:05 +08:00
|
|
|
#define TYPELOC(CLASS, PARENT) \
|
2009-10-18 09:05:36 +08:00
|
|
|
void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
|
2009-10-17 05:56:05 +08:00
|
|
|
#include "clang/AST/TypeLocNodes.def"
|
|
|
|
|
2009-10-18 09:05:36 +08:00
|
|
|
void VisitArrayTypeLoc(ArrayTypeLoc TyLoc);
|
|
|
|
void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc);
|
2009-10-17 05:56:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
|
|
|
// nothing to do
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
|
2010-01-19 02:04:31 +08:00
|
|
|
Writer.AddSourceLocation(TL.getBuiltinLoc(), Record);
|
|
|
|
if (TL.needsExtraLocalData()) {
|
|
|
|
Record.push_back(TL.getWrittenTypeSpec());
|
|
|
|
Record.push_back(TL.getWrittenSignSpec());
|
|
|
|
Record.push_back(TL.getWrittenWidthSpec());
|
|
|
|
Record.push_back(TL.hasModeAttr());
|
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getStarLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getCaretLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getAmpLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getStarLoc(), Record);
|
2011-03-05 22:42:21 +08:00
|
|
|
Writer.AddTypeSourceInfo(TL.getClassTInfo(), Record);
|
2009-10-18 09:05:36 +08:00
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getLBracketLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRBracketLoc(), Record);
|
|
|
|
Record.push_back(TL.getSizeExpr() ? 1 : 0);
|
|
|
|
if (TL.getSizeExpr())
|
|
|
|
Writer.AddStmt(TL.getSizeExpr());
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitDependentSizedArrayTypeLoc(
|
|
|
|
DependentSizedArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc(
|
|
|
|
DependentSizedExtVectorTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
|
2011-03-12 19:17:06 +08:00
|
|
|
Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record);
|
2012-10-05 05:42:10 +08:00
|
|
|
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
|
2011-03-12 19:17:06 +08:00
|
|
|
Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record);
|
2009-10-18 09:05:36 +08:00
|
|
|
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
|
|
|
|
Writer.AddDeclRef(TL.getArg(i), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
|
|
|
|
VisitFunctionTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
|
|
|
|
VisitFunctionTypeLoc(TL);
|
|
|
|
}
|
2009-12-05 06:46:56 +08:00
|
|
|
void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
|
2010-01-14 04:03:27 +08:00
|
|
|
Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
|
2009-10-18 09:05:36 +08:00
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
|
2010-01-14 04:03:27 +08:00
|
|
|
Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
|
|
|
|
Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
|
2009-10-18 09:05:36 +08:00
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2011-05-25 06:41:36 +08:00
|
|
|
void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getKWLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
|
|
|
|
Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
|
|
|
|
}
|
2011-02-20 11:19:35 +08:00
|
|
|
void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2011-01-06 09:58:22 +08:00
|
|
|
void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getAttrNameLoc(), Record);
|
|
|
|
if (TL.hasAttrOperand()) {
|
|
|
|
SourceRange range = TL.getAttrOperandParensRange();
|
|
|
|
Writer.AddSourceLocation(range.getBegin(), Record);
|
|
|
|
Writer.AddSourceLocation(range.getEnd(), Record);
|
|
|
|
}
|
|
|
|
if (TL.hasAttrExprOperand()) {
|
|
|
|
Expr *operand = TL.getAttrExprOperand();
|
|
|
|
Record.push_back(operand ? 1 : 0);
|
|
|
|
if (operand) Writer.AddStmt(operand);
|
|
|
|
} else if (TL.hasAttrEnumOperand()) {
|
|
|
|
Writer.AddSourceLocation(TL.getAttrEnumOperandLoc(), Record);
|
|
|
|
}
|
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2009-10-18 17:09:24 +08:00
|
|
|
void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc(
|
|
|
|
SubstTemplateTypeParmTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
2011-01-14 10:55:32 +08:00
|
|
|
void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc(
|
|
|
|
SubstTemplateTypeParmPackTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
|
|
|
|
TemplateSpecializationTypeLoc TL) {
|
2012-02-06 22:41:24 +08:00
|
|
|
Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record);
|
2009-10-29 16:12:44 +08:00
|
|
|
Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
|
|
|
|
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
|
2010-06-22 17:54:59 +08:00
|
|
|
Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(),
|
|
|
|
TL.getArgLoc(i).getLocInfo(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2010-12-11 00:29:40 +08:00
|
|
|
void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
|
|
|
|
}
|
2010-05-12 05:36:43 +08:00
|
|
|
void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
|
2012-02-07 03:09:27 +08:00
|
|
|
Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
|
2011-03-02 02:12:44 +08:00
|
|
|
Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2010-03-10 11:28:59 +08:00
|
|
|
void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
2010-04-01 01:34:00 +08:00
|
|
|
void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
|
2012-02-07 03:09:27 +08:00
|
|
|
Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
|
2011-03-01 09:34:45 +08:00
|
|
|
Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
|
2009-10-18 09:05:36 +08:00
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2010-06-11 08:33:02 +08:00
|
|
|
void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc(
|
|
|
|
DependentTemplateSpecializationTypeLoc TL) {
|
2012-02-06 22:41:24 +08:00
|
|
|
Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
|
2011-03-02 04:11:18 +08:00
|
|
|
Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
|
2012-02-07 06:45:07 +08:00
|
|
|
Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record);
|
2012-02-06 22:41:24 +08:00
|
|
|
Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);
|
2010-06-11 08:33:02 +08:00
|
|
|
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
|
|
|
|
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
|
2010-06-22 17:54:59 +08:00
|
|
|
Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(),
|
|
|
|
TL.getArgLoc(I).getLocInfo(), Record);
|
2010-06-11 08:33:02 +08:00
|
|
|
}
|
2010-12-20 10:24:11 +08:00
|
|
|
void TypeLocWriter::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getEllipsisLoc(), Record);
|
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2010-05-15 19:32:37 +08:00
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
|
|
|
|
Record.push_back(TL.hasBaseTypeAsWritten());
|
2009-10-23 06:37:11 +08:00
|
|
|
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
|
|
|
|
for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
|
|
|
|
Writer.AddSourceLocation(TL.getProtocolLoc(i), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getStarLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2011-10-07 07:00:33 +08:00
|
|
|
void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getKWLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
|
|
|
|
}
|
2009-10-17 05:56:05 +08:00
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2010-08-19 07:56:21 +08:00
|
|
|
// ASTWriter Implementation
|
2009-04-10 06:27:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-27 06:26:21 +08:00
|
|
|
static void EmitBlockID(unsigned ID, const char *Name,
|
|
|
|
llvm::BitstreamWriter &Stream,
|
2010-10-25 01:26:40 +08:00
|
|
|
ASTWriter::RecordDataImpl &Record) {
|
2009-04-27 06:26:21 +08:00
|
|
|
Record.clear();
|
|
|
|
Record.push_back(ID);
|
|
|
|
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
|
|
|
|
|
|
|
|
// Emit the block name if present.
|
|
|
|
if (Name == 0 || Name[0] == 0) return;
|
|
|
|
Record.clear();
|
|
|
|
while (*Name)
|
|
|
|
Record.push_back(*Name++);
|
|
|
|
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void EmitRecordID(unsigned ID, const char *Name,
|
|
|
|
llvm::BitstreamWriter &Stream,
|
2010-10-25 01:26:40 +08:00
|
|
|
ASTWriter::RecordDataImpl &Record) {
|
2009-04-27 06:26:21 +08:00
|
|
|
Record.clear();
|
|
|
|
Record.push_back(ID);
|
|
|
|
while (*Name)
|
|
|
|
Record.push_back(*Name++);
|
|
|
|
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
|
2009-04-27 08:49:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
|
2010-10-25 01:26:40 +08:00
|
|
|
ASTWriter::RecordDataImpl &Record) {
|
2010-08-19 07:57:32 +08:00
|
|
|
#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
|
2009-04-27 08:49:53 +08:00
|
|
|
RECORD(STMT_STOP);
|
|
|
|
RECORD(STMT_NULL_PTR);
|
|
|
|
RECORD(STMT_NULL);
|
|
|
|
RECORD(STMT_COMPOUND);
|
|
|
|
RECORD(STMT_CASE);
|
|
|
|
RECORD(STMT_DEFAULT);
|
|
|
|
RECORD(STMT_LABEL);
|
2012-04-14 08:33:13 +08:00
|
|
|
RECORD(STMT_ATTRIBUTED);
|
2009-04-27 08:49:53 +08:00
|
|
|
RECORD(STMT_IF);
|
|
|
|
RECORD(STMT_SWITCH);
|
|
|
|
RECORD(STMT_WHILE);
|
|
|
|
RECORD(STMT_DO);
|
|
|
|
RECORD(STMT_FOR);
|
|
|
|
RECORD(STMT_GOTO);
|
|
|
|
RECORD(STMT_INDIRECT_GOTO);
|
|
|
|
RECORD(STMT_CONTINUE);
|
|
|
|
RECORD(STMT_BREAK);
|
|
|
|
RECORD(STMT_RETURN);
|
|
|
|
RECORD(STMT_DECL);
|
2012-08-25 08:11:56 +08:00
|
|
|
RECORD(STMT_GCCASM);
|
2012-08-25 07:51:02 +08:00
|
|
|
RECORD(STMT_MSASM);
|
2009-04-27 08:49:53 +08:00
|
|
|
RECORD(EXPR_PREDEFINED);
|
|
|
|
RECORD(EXPR_DECL_REF);
|
|
|
|
RECORD(EXPR_INTEGER_LITERAL);
|
|
|
|
RECORD(EXPR_FLOATING_LITERAL);
|
|
|
|
RECORD(EXPR_IMAGINARY_LITERAL);
|
|
|
|
RECORD(EXPR_STRING_LITERAL);
|
|
|
|
RECORD(EXPR_CHARACTER_LITERAL);
|
|
|
|
RECORD(EXPR_PAREN);
|
|
|
|
RECORD(EXPR_UNARY_OPERATOR);
|
|
|
|
RECORD(EXPR_SIZEOF_ALIGN_OF);
|
|
|
|
RECORD(EXPR_ARRAY_SUBSCRIPT);
|
|
|
|
RECORD(EXPR_CALL);
|
|
|
|
RECORD(EXPR_MEMBER);
|
|
|
|
RECORD(EXPR_BINARY_OPERATOR);
|
|
|
|
RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR);
|
|
|
|
RECORD(EXPR_CONDITIONAL_OPERATOR);
|
|
|
|
RECORD(EXPR_IMPLICIT_CAST);
|
|
|
|
RECORD(EXPR_CSTYLE_CAST);
|
|
|
|
RECORD(EXPR_COMPOUND_LITERAL);
|
|
|
|
RECORD(EXPR_EXT_VECTOR_ELEMENT);
|
|
|
|
RECORD(EXPR_INIT_LIST);
|
|
|
|
RECORD(EXPR_DESIGNATED_INIT);
|
|
|
|
RECORD(EXPR_IMPLICIT_VALUE_INIT);
|
|
|
|
RECORD(EXPR_VA_ARG);
|
|
|
|
RECORD(EXPR_ADDR_LABEL);
|
|
|
|
RECORD(EXPR_STMT);
|
|
|
|
RECORD(EXPR_CHOOSE);
|
|
|
|
RECORD(EXPR_GNU_NULL);
|
|
|
|
RECORD(EXPR_SHUFFLE_VECTOR);
|
|
|
|
RECORD(EXPR_BLOCK);
|
2011-04-15 08:35:48 +08:00
|
|
|
RECORD(EXPR_GENERIC_SELECTION);
|
2009-04-27 08:49:53 +08:00
|
|
|
RECORD(EXPR_OBJC_STRING_LITERAL);
|
2012-04-19 08:25:12 +08:00
|
|
|
RECORD(EXPR_OBJC_BOXED_EXPRESSION);
|
2012-03-07 04:05:56 +08:00
|
|
|
RECORD(EXPR_OBJC_ARRAY_LITERAL);
|
|
|
|
RECORD(EXPR_OBJC_DICTIONARY_LITERAL);
|
2009-04-27 08:49:53 +08:00
|
|
|
RECORD(EXPR_OBJC_ENCODE);
|
|
|
|
RECORD(EXPR_OBJC_SELECTOR_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_PROTOCOL_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_IVAR_REF_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_PROPERTY_REF_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_KVC_REF_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_MESSAGE_EXPR);
|
|
|
|
RECORD(STMT_OBJC_FOR_COLLECTION);
|
|
|
|
RECORD(STMT_OBJC_CATCH);
|
|
|
|
RECORD(STMT_OBJC_FINALLY);
|
|
|
|
RECORD(STMT_OBJC_AT_TRY);
|
|
|
|
RECORD(STMT_OBJC_AT_SYNCHRONIZED);
|
|
|
|
RECORD(STMT_OBJC_AT_THROW);
|
2012-03-07 04:05:56 +08:00
|
|
|
RECORD(EXPR_OBJC_BOOL_LITERAL);
|
2010-02-07 14:32:43 +08:00
|
|
|
RECORD(EXPR_CXX_OPERATOR_CALL);
|
|
|
|
RECORD(EXPR_CXX_CONSTRUCT);
|
|
|
|
RECORD(EXPR_CXX_STATIC_CAST);
|
|
|
|
RECORD(EXPR_CXX_DYNAMIC_CAST);
|
|
|
|
RECORD(EXPR_CXX_REINTERPRET_CAST);
|
|
|
|
RECORD(EXPR_CXX_CONST_CAST);
|
|
|
|
RECORD(EXPR_CXX_FUNCTIONAL_CAST);
|
2012-03-07 16:35:16 +08:00
|
|
|
RECORD(EXPR_USER_DEFINED_LITERAL);
|
2010-02-07 14:32:43 +08:00
|
|
|
RECORD(EXPR_CXX_BOOL_LITERAL);
|
|
|
|
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
|
2011-02-09 00:34:17 +08:00
|
|
|
RECORD(EXPR_CXX_TYPEID_EXPR);
|
|
|
|
RECORD(EXPR_CXX_TYPEID_TYPE);
|
|
|
|
RECORD(EXPR_CXX_UUIDOF_EXPR);
|
|
|
|
RECORD(EXPR_CXX_UUIDOF_TYPE);
|
|
|
|
RECORD(EXPR_CXX_THIS);
|
|
|
|
RECORD(EXPR_CXX_THROW);
|
|
|
|
RECORD(EXPR_CXX_DEFAULT_ARG);
|
|
|
|
RECORD(EXPR_CXX_BIND_TEMPORARY);
|
|
|
|
RECORD(EXPR_CXX_SCALAR_VALUE_INIT);
|
|
|
|
RECORD(EXPR_CXX_NEW);
|
|
|
|
RECORD(EXPR_CXX_DELETE);
|
|
|
|
RECORD(EXPR_CXX_PSEUDO_DESTRUCTOR);
|
|
|
|
RECORD(EXPR_EXPR_WITH_CLEANUPS);
|
|
|
|
RECORD(EXPR_CXX_DEPENDENT_SCOPE_MEMBER);
|
|
|
|
RECORD(EXPR_CXX_DEPENDENT_SCOPE_DECL_REF);
|
|
|
|
RECORD(EXPR_CXX_UNRESOLVED_CONSTRUCT);
|
|
|
|
RECORD(EXPR_CXX_UNRESOLVED_MEMBER);
|
|
|
|
RECORD(EXPR_CXX_UNRESOLVED_LOOKUP);
|
|
|
|
RECORD(EXPR_CXX_UNARY_TYPE_TRAIT);
|
|
|
|
RECORD(EXPR_CXX_NOEXCEPT);
|
|
|
|
RECORD(EXPR_OPAQUE_VALUE);
|
|
|
|
RECORD(EXPR_BINARY_TYPE_TRAIT);
|
|
|
|
RECORD(EXPR_PACK_EXPANSION);
|
|
|
|
RECORD(EXPR_SIZEOF_PACK);
|
|
|
|
RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK);
|
2011-02-10 05:07:24 +08:00
|
|
|
RECORD(EXPR_CUDA_KERNEL_CALL);
|
2009-04-27 08:49:53 +08:00
|
|
|
#undef RECORD
|
2009-04-27 06:26:21 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteBlockInfoBlock() {
|
2009-04-27 06:26:21 +08:00
|
|
|
RecordData Record;
|
|
|
|
Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
#define BLOCK(X) EmitBlockID(X ## _ID, #X, Stream, Record)
|
|
|
|
#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-10-19 02:27:37 +08:00
|
|
|
// Control Block.
|
|
|
|
BLOCK(CONTROL_BLOCK);
|
|
|
|
RECORD(METADATA);
|
|
|
|
RECORD(IMPORTS);
|
|
|
|
RECORD(LANGUAGE_OPTIONS);
|
|
|
|
RECORD(TARGET_OPTIONS);
|
2012-10-19 02:36:53 +08:00
|
|
|
RECORD(ORIGINAL_FILE);
|
2012-10-19 02:27:37 +08:00
|
|
|
RECORD(ORIGINAL_PCH_DIR);
|
2012-10-23 02:42:04 +08:00
|
|
|
RECORD(INPUT_FILE_OFFSETS);
|
2012-10-24 23:17:15 +08:00
|
|
|
RECORD(DIAGNOSTIC_OPTIONS);
|
2012-10-24 23:49:58 +08:00
|
|
|
RECORD(FILE_SYSTEM_OPTIONS);
|
2012-10-25 00:50:34 +08:00
|
|
|
RECORD(HEADER_SEARCH_OPTIONS);
|
2012-10-24 23:49:58 +08:00
|
|
|
|
2012-10-19 08:45:00 +08:00
|
|
|
BLOCK(INPUT_FILES_BLOCK);
|
|
|
|
RECORD(INPUT_FILE);
|
|
|
|
|
2012-10-19 02:27:37 +08:00
|
|
|
// AST Top-Level Block.
|
|
|
|
BLOCK(AST_BLOCK);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(TYPE_OFFSET);
|
|
|
|
RECORD(DECL_OFFSET);
|
|
|
|
RECORD(IDENTIFIER_OFFSET);
|
|
|
|
RECORD(IDENTIFIER_TABLE);
|
|
|
|
RECORD(EXTERNAL_DEFINITIONS);
|
|
|
|
RECORD(SPECIAL_TYPES);
|
|
|
|
RECORD(STATISTICS);
|
|
|
|
RECORD(TENTATIVE_DEFINITIONS);
|
2010-08-14 02:42:17 +08:00
|
|
|
RECORD(UNUSED_FILESCOPED_DECLS);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
|
|
|
|
RECORD(SELECTOR_OFFSETS);
|
|
|
|
RECORD(METHOD_POOL);
|
|
|
|
RECORD(PP_COUNTER_VALUE);
|
2009-04-27 14:38:32 +08:00
|
|
|
RECORD(SOURCE_LOCATION_OFFSETS);
|
|
|
|
RECORD(SOURCE_LOCATION_PRELOADS);
|
2009-04-28 02:38:38 +08:00
|
|
|
RECORD(STAT_CACHE);
|
2009-04-28 04:06:05 +08:00
|
|
|
RECORD(EXT_VECTOR_DECLS);
|
2011-09-16 02:02:56 +08:00
|
|
|
RECORD(PPD_ENTITIES_OFFSETS);
|
2010-07-24 03:11:11 +08:00
|
|
|
RECORD(REFERENCED_SELECTOR_POOL);
|
2011-02-09 00:34:17 +08:00
|
|
|
RECORD(TU_UPDATE_LEXICAL);
|
2012-01-16 00:58:34 +08:00
|
|
|
RECORD(LOCAL_REDECLARATIONS_MAP);
|
2011-02-09 00:34:17 +08:00
|
|
|
RECORD(SEMA_DECL_REFS);
|
|
|
|
RECORD(WEAK_UNDECLARED_IDENTIFIERS);
|
|
|
|
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
|
|
|
|
RECORD(DECL_REPLACEMENTS);
|
|
|
|
RECORD(UPDATE_VISIBLE);
|
|
|
|
RECORD(DECL_UPDATE_OFFSETS);
|
|
|
|
RECORD(DECL_UPDATES);
|
|
|
|
RECORD(CXX_BASE_SPECIFIER_OFFSETS);
|
|
|
|
RECORD(DIAG_PRAGMA_MAPPINGS);
|
2011-02-16 03:46:30 +08:00
|
|
|
RECORD(CUDA_SPECIAL_DECL_REFS);
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
RECORD(HEADER_SEARCH_TABLE);
|
2011-02-16 03:46:30 +08:00
|
|
|
RECORD(FP_PRAGMA_OPTIONS);
|
|
|
|
RECORD(OPENCL_EXTENSIONS);
|
2011-05-05 07:29:54 +08:00
|
|
|
RECORD(DELEGATING_CTORS);
|
2011-06-29 00:20:02 +08:00
|
|
|
RECORD(KNOWN_NAMESPACES);
|
2011-08-05 00:39:39 +08:00
|
|
|
RECORD(MODULE_OFFSET_MAP);
|
|
|
|
RECORD(SOURCE_MANAGER_LINE_TABLE);
|
2012-01-27 09:47:08 +08:00
|
|
|
RECORD(OBJC_CATEGORIES_MAP);
|
2011-12-20 05:09:25 +08:00
|
|
|
RECORD(FILE_SORTED_DECLS);
|
|
|
|
RECORD(IMPORTED_MODULES);
|
2012-01-16 00:58:34 +08:00
|
|
|
RECORD(MERGED_DECLARATIONS);
|
|
|
|
RECORD(LOCAL_REDECLARATIONS);
|
2012-01-27 09:47:08 +08:00
|
|
|
RECORD(OBJC_CATEGORIES);
|
2012-10-10 07:05:51 +08:00
|
|
|
RECORD(MACRO_OFFSET);
|
|
|
|
RECORD(MACRO_UPDATES);
|
2012-01-16 00:58:34 +08:00
|
|
|
|
2009-04-27 06:26:21 +08:00
|
|
|
// SourceManager Block.
|
2009-04-27 08:40:25 +08:00
|
|
|
BLOCK(SOURCE_MANAGER_BLOCK);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(SM_SLOC_FILE_ENTRY);
|
|
|
|
RECORD(SM_SLOC_BUFFER_ENTRY);
|
|
|
|
RECORD(SM_SLOC_BUFFER_BLOB);
|
2011-07-15 15:25:21 +08:00
|
|
|
RECORD(SM_SLOC_EXPANSION_ENTRY);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-27 06:26:21 +08:00
|
|
|
// Preprocessor Block.
|
2009-04-27 08:40:25 +08:00
|
|
|
BLOCK(PREPROCESSOR_BLOCK);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(PP_MACRO_OBJECT_LIKE);
|
|
|
|
RECORD(PP_MACRO_FUNCTION_LIKE);
|
|
|
|
RECORD(PP_TOKEN);
|
2011-02-09 00:34:17 +08:00
|
|
|
|
2009-10-17 08:13:19 +08:00
|
|
|
// Decls and Types block.
|
|
|
|
BLOCK(DECLTYPES_BLOCK);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(TYPE_EXT_QUAL);
|
|
|
|
RECORD(TYPE_COMPLEX);
|
|
|
|
RECORD(TYPE_POINTER);
|
|
|
|
RECORD(TYPE_BLOCK_POINTER);
|
|
|
|
RECORD(TYPE_LVALUE_REFERENCE);
|
|
|
|
RECORD(TYPE_RVALUE_REFERENCE);
|
|
|
|
RECORD(TYPE_MEMBER_POINTER);
|
|
|
|
RECORD(TYPE_CONSTANT_ARRAY);
|
|
|
|
RECORD(TYPE_INCOMPLETE_ARRAY);
|
|
|
|
RECORD(TYPE_VARIABLE_ARRAY);
|
|
|
|
RECORD(TYPE_VECTOR);
|
|
|
|
RECORD(TYPE_EXT_VECTOR);
|
|
|
|
RECORD(TYPE_FUNCTION_PROTO);
|
|
|
|
RECORD(TYPE_FUNCTION_NO_PROTO);
|
|
|
|
RECORD(TYPE_TYPEDEF);
|
|
|
|
RECORD(TYPE_TYPEOF_EXPR);
|
|
|
|
RECORD(TYPE_TYPEOF);
|
|
|
|
RECORD(TYPE_RECORD);
|
|
|
|
RECORD(TYPE_ENUM);
|
|
|
|
RECORD(TYPE_OBJC_INTERFACE);
|
2010-05-16 10:12:35 +08:00
|
|
|
RECORD(TYPE_OBJC_OBJECT);
|
2009-06-18 06:40:22 +08:00
|
|
|
RECORD(TYPE_OBJC_OBJECT_POINTER);
|
2011-02-09 00:34:17 +08:00
|
|
|
RECORD(TYPE_DECLTYPE);
|
|
|
|
RECORD(TYPE_ELABORATED);
|
|
|
|
RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM);
|
|
|
|
RECORD(TYPE_UNRESOLVED_USING);
|
|
|
|
RECORD(TYPE_INJECTED_CLASS_NAME);
|
|
|
|
RECORD(TYPE_OBJC_OBJECT);
|
|
|
|
RECORD(TYPE_TEMPLATE_TYPE_PARM);
|
|
|
|
RECORD(TYPE_TEMPLATE_SPECIALIZATION);
|
|
|
|
RECORD(TYPE_DEPENDENT_NAME);
|
|
|
|
RECORD(TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION);
|
|
|
|
RECORD(TYPE_DEPENDENT_SIZED_ARRAY);
|
|
|
|
RECORD(TYPE_PAREN);
|
|
|
|
RECORD(TYPE_PACK_EXPANSION);
|
|
|
|
RECORD(TYPE_ATTRIBUTED);
|
|
|
|
RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
|
2011-10-07 07:00:33 +08:00
|
|
|
RECORD(TYPE_ATOMIC);
|
2009-04-27 06:32:16 +08:00
|
|
|
RECORD(DECL_TYPEDEF);
|
|
|
|
RECORD(DECL_ENUM);
|
|
|
|
RECORD(DECL_RECORD);
|
|
|
|
RECORD(DECL_ENUM_CONSTANT);
|
|
|
|
RECORD(DECL_FUNCTION);
|
|
|
|
RECORD(DECL_OBJC_METHOD);
|
|
|
|
RECORD(DECL_OBJC_INTERFACE);
|
|
|
|
RECORD(DECL_OBJC_PROTOCOL);
|
|
|
|
RECORD(DECL_OBJC_IVAR);
|
|
|
|
RECORD(DECL_OBJC_AT_DEFS_FIELD);
|
|
|
|
RECORD(DECL_OBJC_CATEGORY);
|
|
|
|
RECORD(DECL_OBJC_CATEGORY_IMPL);
|
|
|
|
RECORD(DECL_OBJC_IMPLEMENTATION);
|
|
|
|
RECORD(DECL_OBJC_COMPATIBLE_ALIAS);
|
|
|
|
RECORD(DECL_OBJC_PROPERTY);
|
|
|
|
RECORD(DECL_OBJC_PROPERTY_IMPL);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(DECL_FIELD);
|
|
|
|
RECORD(DECL_VAR);
|
2009-04-27 06:32:16 +08:00
|
|
|
RECORD(DECL_IMPLICIT_PARAM);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(DECL_PARM_VAR);
|
2009-04-27 06:32:16 +08:00
|
|
|
RECORD(DECL_FILE_SCOPE_ASM);
|
|
|
|
RECORD(DECL_BLOCK);
|
|
|
|
RECORD(DECL_CONTEXT_LEXICAL);
|
|
|
|
RECORD(DECL_CONTEXT_VISIBLE);
|
2011-02-09 00:34:17 +08:00
|
|
|
RECORD(DECL_NAMESPACE);
|
|
|
|
RECORD(DECL_NAMESPACE_ALIAS);
|
|
|
|
RECORD(DECL_USING);
|
|
|
|
RECORD(DECL_USING_SHADOW);
|
|
|
|
RECORD(DECL_USING_DIRECTIVE);
|
|
|
|
RECORD(DECL_UNRESOLVED_USING_VALUE);
|
|
|
|
RECORD(DECL_UNRESOLVED_USING_TYPENAME);
|
|
|
|
RECORD(DECL_LINKAGE_SPEC);
|
|
|
|
RECORD(DECL_CXX_RECORD);
|
|
|
|
RECORD(DECL_CXX_METHOD);
|
|
|
|
RECORD(DECL_CXX_CONSTRUCTOR);
|
|
|
|
RECORD(DECL_CXX_DESTRUCTOR);
|
|
|
|
RECORD(DECL_CXX_CONVERSION);
|
|
|
|
RECORD(DECL_ACCESS_SPEC);
|
|
|
|
RECORD(DECL_FRIEND);
|
|
|
|
RECORD(DECL_FRIEND_TEMPLATE);
|
|
|
|
RECORD(DECL_CLASS_TEMPLATE);
|
|
|
|
RECORD(DECL_CLASS_TEMPLATE_SPECIALIZATION);
|
|
|
|
RECORD(DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION);
|
|
|
|
RECORD(DECL_FUNCTION_TEMPLATE);
|
|
|
|
RECORD(DECL_TEMPLATE_TYPE_PARM);
|
|
|
|
RECORD(DECL_NON_TYPE_TEMPLATE_PARM);
|
|
|
|
RECORD(DECL_TEMPLATE_TEMPLATE_PARM);
|
|
|
|
RECORD(DECL_STATIC_ASSERT);
|
|
|
|
RECORD(DECL_CXX_BASE_SPECIFIERS);
|
|
|
|
RECORD(DECL_INDIRECTFIELD);
|
|
|
|
RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK);
|
|
|
|
|
2011-06-03 10:27:19 +08:00
|
|
|
// Statements and Exprs can occur in the Decls and Types block.
|
|
|
|
AddStmtsExprs(Stream, Record);
|
|
|
|
|
2011-02-09 05:58:10 +08:00
|
|
|
BLOCK(PREPROCESSOR_DETAIL_BLOCK);
|
2011-07-15 15:25:21 +08:00
|
|
|
RECORD(PPD_MACRO_EXPANSION);
|
2011-02-09 05:58:10 +08:00
|
|
|
RECORD(PPD_MACRO_DEFINITION);
|
|
|
|
RECORD(PPD_INCLUSION_DIRECTIVE);
|
|
|
|
|
2009-04-27 06:26:21 +08:00
|
|
|
#undef RECORD
|
|
|
|
#undef BLOCK
|
|
|
|
Stream.ExitBlock();
|
|
|
|
}
|
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
/// \brief Adjusts the given filename to only write out the portion of the
|
|
|
|
/// filename that is not part of the system root directory.
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2009-07-07 08:12:59 +08:00
|
|
|
/// \param Filename the file name to adjust.
|
|
|
|
///
|
|
|
|
/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and
|
|
|
|
/// the returned filename will be adjusted by this system root.
|
|
|
|
///
|
|
|
|
/// \returns either the original filename (if it needs no adjustment) or the
|
|
|
|
/// adjusted filename (which points into the @p Filename parameter).
|
2009-09-09 23:08:12 +08:00
|
|
|
static const char *
|
2011-07-23 00:35:34 +08:00
|
|
|
adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) {
|
2009-07-07 08:12:59 +08:00
|
|
|
assert(Filename && "No file name to adjust?");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 00:35:34 +08:00
|
|
|
if (isysroot.empty())
|
2009-07-07 08:12:59 +08:00
|
|
|
return Filename;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
// Verify that the filename and the system root have the same prefix.
|
|
|
|
unsigned Pos = 0;
|
2011-07-23 00:35:34 +08:00
|
|
|
for (; Filename[Pos] && Pos < isysroot.size(); ++Pos)
|
2009-07-07 08:12:59 +08:00
|
|
|
if (Filename[Pos] != isysroot[Pos])
|
|
|
|
return Filename; // Prefixes don't match.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
// We hit the end of the filename before we hit the end of the system root.
|
|
|
|
if (!Filename[Pos])
|
|
|
|
return Filename;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
// If the file name has a '/' at the current position, skip over the '/'.
|
|
|
|
// We distinguish sysroot-based includes from absolute includes by the
|
|
|
|
// absence of '/' at the beginning of sysroot-based includes.
|
|
|
|
if (Filename[Pos] == '/')
|
|
|
|
++Pos;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
return Filename + Pos;
|
|
|
|
}
|
2009-04-27 06:26:21 +08:00
|
|
|
|
2012-10-18 13:31:06 +08:00
|
|
|
/// \brief Write the control block.
|
2012-10-25 00:50:34 +08:00
|
|
|
void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
|
|
|
|
StringRef isysroot,
|
2012-10-18 13:31:06 +08:00
|
|
|
const std::string &OutputFile) {
|
2009-04-11 05:16:55 +08:00
|
|
|
using namespace llvm;
|
2012-10-19 02:27:37 +08:00
|
|
|
Stream.EnterSubblock(CONTROL_BLOCK_ID, 5);
|
|
|
|
RecordData Record;
|
2012-10-18 13:31:06 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
// Metadata
|
2012-10-19 02:27:37 +08:00
|
|
|
BitCodeAbbrev *MetadataAbbrev = new BitCodeAbbrev();
|
|
|
|
MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA));
|
|
|
|
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major
|
|
|
|
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor
|
|
|
|
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang maj.
|
|
|
|
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang min.
|
|
|
|
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
|
|
|
|
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors
|
|
|
|
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
|
|
|
|
unsigned MetadataAbbrevCode = Stream.EmitAbbrev(MetadataAbbrev);
|
|
|
|
Record.push_back(METADATA);
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(VERSION_MAJOR);
|
|
|
|
Record.push_back(VERSION_MINOR);
|
2009-07-07 08:12:59 +08:00
|
|
|
Record.push_back(CLANG_VERSION_MAJOR);
|
|
|
|
Record.push_back(CLANG_VERSION_MINOR);
|
2011-07-23 00:35:34 +08:00
|
|
|
Record.push_back(!isysroot.empty());
|
2012-03-07 09:51:17 +08:00
|
|
|
Record.push_back(ASTHasCompilerErrors);
|
2012-10-19 02:27:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
|
|
|
|
getClangFullRepositoryVersion());
|
2011-08-18 05:07:30 +08:00
|
|
|
|
2012-10-18 13:31:06 +08:00
|
|
|
// Imports
|
2011-08-18 05:07:30 +08:00
|
|
|
if (Chain) {
|
|
|
|
serialization::ModuleManager &Mgr = Chain->getModuleManager();
|
|
|
|
llvm::SmallVector<char, 128> ModulePaths;
|
|
|
|
Record.clear();
|
2011-08-18 12:12:04 +08:00
|
|
|
|
|
|
|
for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end();
|
|
|
|
M != MEnd; ++M) {
|
|
|
|
// Skip modules that weren't directly imported.
|
|
|
|
if (!(*M)->isDirectlyImported())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding
|
|
|
|
// FIXME: Write import location, once it matters.
|
|
|
|
// FIXME: This writes the absolute path for AST files we depend on.
|
|
|
|
const std::string &FileName = (*M)->FileName;
|
|
|
|
Record.push_back(FileName.size());
|
|
|
|
Record.append(FileName.begin(), FileName.end());
|
|
|
|
}
|
2011-08-18 05:07:30 +08:00
|
|
|
Stream.EmitRecord(IMPORTS, Record);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-10-18 13:31:06 +08:00
|
|
|
// Language options.
|
|
|
|
Record.clear();
|
|
|
|
const LangOptions &LangOpts = Context.getLangOpts();
|
|
|
|
#define LANGOPT(Name, Bits, Default, Description) \
|
|
|
|
Record.push_back(LangOpts.Name);
|
|
|
|
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
|
|
|
|
Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
|
|
|
|
#include "clang/Basic/LangOptions.def"
|
|
|
|
|
|
|
|
Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind());
|
|
|
|
AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record);
|
|
|
|
|
|
|
|
Record.push_back(LangOpts.CurrentModule.size());
|
|
|
|
Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end());
|
|
|
|
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
|
|
|
|
|
2012-10-19 01:58:09 +08:00
|
|
|
// Target options.
|
|
|
|
Record.clear();
|
2012-10-19 02:27:37 +08:00
|
|
|
const TargetInfo &Target = Context.getTargetInfo();
|
|
|
|
const TargetOptions &TargetOpts = Target.getTargetOpts();
|
2012-10-19 01:58:09 +08:00
|
|
|
AddString(TargetOpts.Triple, Record);
|
|
|
|
AddString(TargetOpts.CPU, Record);
|
|
|
|
AddString(TargetOpts.ABI, Record);
|
|
|
|
AddString(TargetOpts.CXXABI, Record);
|
|
|
|
AddString(TargetOpts.LinkerVersion, Record);
|
|
|
|
Record.push_back(TargetOpts.FeaturesAsWritten.size());
|
|
|
|
for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) {
|
|
|
|
AddString(TargetOpts.FeaturesAsWritten[I], Record);
|
|
|
|
}
|
|
|
|
Record.push_back(TargetOpts.Features.size());
|
|
|
|
for (unsigned I = 0, N = TargetOpts.Features.size(); I != N; ++I) {
|
|
|
|
AddString(TargetOpts.Features[I], Record);
|
|
|
|
}
|
|
|
|
Stream.EmitRecord(TARGET_OPTIONS, Record);
|
|
|
|
|
2012-10-24 23:17:15 +08:00
|
|
|
// Diagnostic options.
|
|
|
|
Record.clear();
|
|
|
|
const DiagnosticOptions &DiagOpts
|
|
|
|
= Context.getDiagnostics().getDiagnosticOptions();
|
|
|
|
#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name);
|
|
|
|
#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
|
|
|
|
Record.push_back(static_cast<unsigned>(DiagOpts.get##Name()));
|
|
|
|
#include "clang/Basic/DiagnosticOptions.def"
|
|
|
|
Record.push_back(DiagOpts.Warnings.size());
|
|
|
|
for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
|
|
|
|
AddString(DiagOpts.Warnings[I], Record);
|
|
|
|
// Note: we don't serialize the log or serialization file names, because they
|
|
|
|
// are generally transient files and will almost always be overridden.
|
|
|
|
Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
|
|
|
|
|
2012-10-24 23:49:58 +08:00
|
|
|
// File system options.
|
|
|
|
Record.clear();
|
|
|
|
const FileSystemOptions &FSOpts
|
|
|
|
= Context.getSourceManager().getFileManager().getFileSystemOptions();
|
|
|
|
AddString(FSOpts.WorkingDir, Record);
|
|
|
|
Stream.EmitRecord(FILE_SYSTEM_OPTIONS, Record);
|
|
|
|
|
2012-10-25 00:50:34 +08:00
|
|
|
// Header search options.
|
|
|
|
Record.clear();
|
|
|
|
const HeaderSearchOptions &HSOpts
|
|
|
|
= PP.getHeaderSearchInfo().getHeaderSearchOpts();
|
|
|
|
AddString(HSOpts.Sysroot, Record);
|
|
|
|
|
|
|
|
// Include entries.
|
|
|
|
Record.push_back(HSOpts.UserEntries.size());
|
|
|
|
for (unsigned I = 0, N = HSOpts.UserEntries.size(); I != N; ++I) {
|
|
|
|
const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I];
|
|
|
|
AddString(Entry.Path, Record);
|
|
|
|
Record.push_back(static_cast<unsigned>(Entry.Group));
|
|
|
|
Record.push_back(Entry.IsUserSupplied);
|
|
|
|
Record.push_back(Entry.IsFramework);
|
|
|
|
Record.push_back(Entry.IgnoreSysRoot);
|
|
|
|
Record.push_back(Entry.IsInternal);
|
|
|
|
Record.push_back(Entry.ImplicitExternC);
|
|
|
|
}
|
|
|
|
|
|
|
|
// System header prefixes.
|
|
|
|
Record.push_back(HSOpts.SystemHeaderPrefixes.size());
|
|
|
|
for (unsigned I = 0, N = HSOpts.SystemHeaderPrefixes.size(); I != N; ++I) {
|
|
|
|
AddString(HSOpts.SystemHeaderPrefixes[I].Prefix, Record);
|
|
|
|
Record.push_back(HSOpts.SystemHeaderPrefixes[I].IsSystemHeader);
|
|
|
|
}
|
|
|
|
|
|
|
|
AddString(HSOpts.ResourceDir, Record);
|
|
|
|
AddString(HSOpts.ModuleCachePath, Record);
|
|
|
|
Record.push_back(HSOpts.DisableModuleHash);
|
|
|
|
Record.push_back(HSOpts.UseBuiltinIncludes);
|
|
|
|
Record.push_back(HSOpts.UseStandardSystemIncludes);
|
|
|
|
Record.push_back(HSOpts.UseStandardCXXIncludes);
|
|
|
|
Record.push_back(HSOpts.UseLibcxx);
|
|
|
|
Stream.EmitRecord(HEADER_SEARCH_OPTIONS, Record);
|
|
|
|
|
2011-05-07 05:43:30 +08:00
|
|
|
// Original file name and file ID
|
2009-05-12 09:31:05 +08:00
|
|
|
SourceManager &SM = Context.getSourceManager();
|
|
|
|
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
|
|
|
|
BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
|
2012-10-19 02:36:53 +08:00
|
|
|
FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE));
|
|
|
|
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID
|
2009-05-12 09:31:05 +08:00
|
|
|
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
|
|
|
|
unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
|
|
|
|
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<128> MainFilePath(MainFile->getName());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-12-22 00:45:57 +08:00
|
|
|
llvm::sys::fs::make_absolute(MainFilePath);
|
2009-05-12 09:31:05 +08:00
|
|
|
|
2010-03-14 15:15:57 +08:00
|
|
|
const char *MainFileNameStr = MainFilePath.c_str();
|
2009-09-09 23:08:12 +08:00
|
|
|
MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
|
2009-07-07 08:12:59 +08:00
|
|
|
isysroot);
|
2009-05-12 09:31:05 +08:00
|
|
|
RecordData Record;
|
2012-10-19 02:36:53 +08:00
|
|
|
Record.push_back(ORIGINAL_FILE);
|
|
|
|
Record.push_back(SM.getMainFileID().getOpaqueValue());
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
|
2011-05-07 05:43:30 +08:00
|
|
|
Record.clear();
|
2009-05-12 09:31:05 +08:00
|
|
|
}
|
2010-03-14 15:06:50 +08:00
|
|
|
|
2011-02-16 01:54:22 +08:00
|
|
|
// Original PCH directory
|
|
|
|
if (!OutputFile.empty() && OutputFile != "-") {
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
|
|
|
|
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<128> OutputPath(OutputFile);
|
2011-02-16 01:54:22 +08:00
|
|
|
|
|
|
|
llvm::sys::fs::make_absolute(OutputPath);
|
|
|
|
StringRef origDir = llvm::sys::path::parent_path(OutputPath);
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(ORIGINAL_PCH_DIR);
|
|
|
|
Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
|
|
|
|
}
|
|
|
|
|
2012-10-19 08:38:02 +08:00
|
|
|
WriteInputFiles(Context.SourceMgr, isysroot);
|
|
|
|
Stream.ExitBlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
|
|
|
|
using namespace llvm;
|
|
|
|
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
|
|
|
|
RecordData Record;
|
|
|
|
|
|
|
|
// Create input-file abbreviation.
|
|
|
|
BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev();
|
|
|
|
IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE));
|
2012-10-23 02:42:04 +08:00
|
|
|
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
|
2012-10-19 08:38:02 +08:00
|
|
|
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
|
|
|
|
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
|
2012-10-23 02:42:04 +08:00
|
|
|
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden
|
2012-10-19 08:38:02 +08:00
|
|
|
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
|
|
|
|
unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
|
|
|
|
|
|
|
|
// Write out all of the input files.
|
|
|
|
std::vector<uint32_t> InputFileOffsets;
|
|
|
|
for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
|
|
|
|
// Get this source location entry.
|
|
|
|
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
|
2012-10-19 09:53:57 +08:00
|
|
|
assert(&SourceMgr.getSLocEntry(FileID::get(I)) == SLoc);
|
2012-10-19 08:38:02 +08:00
|
|
|
|
|
|
|
// We only care about file entries that were not overridden.
|
|
|
|
if (!SLoc->isFile())
|
|
|
|
continue;
|
|
|
|
const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
|
2012-10-23 02:42:04 +08:00
|
|
|
if (!Cache->OrigEntry)
|
2012-10-19 08:38:02 +08:00
|
|
|
continue;
|
|
|
|
|
2012-10-23 02:42:04 +08:00
|
|
|
// Record this entry's offset.
|
|
|
|
InputFileOffsets.push_back(Stream.GetCurrentBitNo());
|
|
|
|
InputFileIDs[Cache->OrigEntry] = InputFileOffsets.size();
|
|
|
|
|
2012-10-19 08:38:02 +08:00
|
|
|
Record.clear();
|
|
|
|
Record.push_back(INPUT_FILE);
|
2012-10-23 02:42:04 +08:00
|
|
|
Record.push_back(InputFileOffsets.size());
|
2012-10-19 08:38:02 +08:00
|
|
|
|
|
|
|
// Emit size/modification time for this file.
|
|
|
|
Record.push_back(Cache->OrigEntry->getSize());
|
|
|
|
Record.push_back(Cache->OrigEntry->getModificationTime());
|
|
|
|
|
2012-10-23 02:42:04 +08:00
|
|
|
// Whether this file was overridden.
|
|
|
|
Record.push_back(Cache->BufferOverridden);
|
|
|
|
|
2012-10-19 08:38:02 +08:00
|
|
|
// Turn the file name into an absolute path, if it isn't already.
|
|
|
|
const char *Filename = Cache->OrigEntry->getName();
|
|
|
|
SmallString<128> FilePath(Filename);
|
|
|
|
|
|
|
|
// Ask the file manager to fixup the relative path for us. This will
|
|
|
|
// honor the working directory.
|
|
|
|
SourceMgr.getFileManager().FixupRelativePath(FilePath);
|
|
|
|
|
|
|
|
// FIXME: This call to make_absolute shouldn't be necessary, the
|
|
|
|
// call to FixupRelativePath should always return an absolute path.
|
|
|
|
llvm::sys::fs::make_absolute(FilePath);
|
|
|
|
Filename = FilePath.c_str();
|
|
|
|
|
|
|
|
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
|
|
|
|
|
|
|
|
Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
|
|
|
|
}
|
|
|
|
|
2012-10-18 13:31:06 +08:00
|
|
|
Stream.ExitBlock();
|
2012-10-23 02:42:04 +08:00
|
|
|
|
|
|
|
// Create input file offsets abbreviation.
|
|
|
|
BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev();
|
|
|
|
OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS));
|
|
|
|
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files
|
|
|
|
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array
|
|
|
|
unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);
|
|
|
|
|
|
|
|
// Write input file offsets.
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(INPUT_FILE_OFFSETS);
|
|
|
|
Record.push_back(InputFileOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets));
|
2009-04-11 04:39:37 +08:00
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// stat cache Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// Trait used for the on-disk hash table of stat cache results.
|
2010-08-19 07:56:27 +08:00
|
|
|
class ASTStatCacheTrait {
|
2009-04-28 02:38:38 +08:00
|
|
|
public:
|
|
|
|
typedef const char * key_type;
|
|
|
|
typedef key_type key_type_ref;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-24 03:28:12 +08:00
|
|
|
typedef struct stat data_type;
|
|
|
|
typedef const data_type &data_type_ref;
|
2009-04-28 02:38:38 +08:00
|
|
|
|
|
|
|
static unsigned ComputeHash(const char *path) {
|
2009-10-18 07:52:28 +08:00
|
|
|
return llvm::HashString(path);
|
2009-04-28 02:38:38 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
2011-07-23 18:55:15 +08:00
|
|
|
EmitKeyDataLength(raw_ostream& Out, const char *path,
|
2009-04-28 02:38:38 +08:00
|
|
|
data_type_ref Data) {
|
|
|
|
unsigned StrLen = strlen(path);
|
|
|
|
clang::io::Emit16(Out, StrLen);
|
2010-11-24 03:28:12 +08:00
|
|
|
unsigned DataLen = 4 + 4 + 2 + 8 + 8;
|
2009-04-28 02:38:38 +08:00
|
|
|
clang::io::Emit8(Out, DataLen);
|
|
|
|
return std::make_pair(StrLen + 1, DataLen);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
|
2009-04-28 02:38:38 +08:00
|
|
|
Out.write(path, KeyLen);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void EmitData(raw_ostream &Out, key_type_ref,
|
2009-04-28 02:38:38 +08:00
|
|
|
data_type_ref Data, unsigned DataLen) {
|
|
|
|
using namespace clang::io;
|
|
|
|
uint64_t Start = Out.tell(); (void)Start;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-24 03:28:12 +08:00
|
|
|
Emit32(Out, (uint32_t) Data.st_ino);
|
|
|
|
Emit32(Out, (uint32_t) Data.st_dev);
|
|
|
|
Emit16(Out, (uint16_t) Data.st_mode);
|
|
|
|
Emit64(Out, (uint64_t) Data.st_mtime);
|
|
|
|
Emit64(Out, (uint64_t) Data.st_size);
|
2009-04-28 02:38:38 +08:00
|
|
|
|
|
|
|
assert(Out.tell() - Start == DataLen && "Wrong data length");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
/// \brief Write the stat() system call cache to the AST file.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
|
2009-04-28 02:38:38 +08:00
|
|
|
// Build the on-disk hash table containing information about every
|
|
|
|
// stat() call.
|
2010-08-19 07:56:27 +08:00
|
|
|
OnDiskChainedHashTableGenerator<ASTStatCacheTrait> Generator;
|
2009-04-28 02:38:38 +08:00
|
|
|
unsigned NumStatEntries = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
|
2009-04-28 02:38:38 +08:00
|
|
|
StatEnd = StatCalls.end();
|
2009-07-07 08:12:59 +08:00
|
|
|
Stat != StatEnd; ++Stat, ++NumStatEntries) {
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef Filename = Stat->first();
|
2011-07-15 02:24:21 +08:00
|
|
|
Generator.insert(Filename.data(), Stat->second);
|
2009-07-07 08:12:59 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
// Create the on-disk hash table in a buffer.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<4096> StatCacheData;
|
2009-04-28 02:38:38 +08:00
|
|
|
uint32_t BucketOffset;
|
|
|
|
{
|
|
|
|
llvm::raw_svector_ostream Out(StatCacheData);
|
|
|
|
// Make sure that no bucket is at offset 0
|
|
|
|
clang::io::Emit32(Out, 0);
|
|
|
|
BucketOffset = Generator.Emit(Out);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a blob abbreviation
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(STAT_CACHE));
|
2009-04-28 02:38:38 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
// Write the stat cache
|
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(STAT_CACHE);
|
2009-04-28 02:38:38 +08:00
|
|
|
Record.push_back(BucketOffset);
|
|
|
|
Record.push_back(NumStatEntries);
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str());
|
2009-04-28 02:38:38 +08:00
|
|
|
}
|
|
|
|
|
2009-04-10 11:52:48 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Source Manager Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// \brief Create an abbreviation for the SLocEntry that refers to a
|
|
|
|
/// file.
|
2009-04-17 06:23:12 +08:00
|
|
|
static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
|
2009-04-10 11:52:48 +08:00
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY));
|
2009-04-10 11:52:48 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
|
2010-03-22 06:49:54 +08:00
|
|
|
// FileEntry fields.
|
2012-10-23 02:42:04 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID
|
2011-08-22 07:33:04 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs
|
2011-10-29 06:54:21 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls
|
2009-04-17 06:23:12 +08:00
|
|
|
return Stream.EmitAbbrev(Abbrev);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Create an abbreviation for the SLocEntry that refers to a
|
|
|
|
/// buffer.
|
2009-04-17 06:23:12 +08:00
|
|
|
static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {
|
2009-04-10 11:52:48 +08:00
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY));
|
2009-04-10 11:52:48 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob
|
2009-04-17 06:23:12 +08:00
|
|
|
return Stream.EmitAbbrev(Abbrev);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Create an abbreviation for the SLocEntry that refers to a
|
|
|
|
/// buffer's blob.
|
2009-04-17 06:23:12 +08:00
|
|
|
static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {
|
2009-04-10 11:52:48 +08:00
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_BLOB));
|
2009-04-10 11:52:48 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob
|
2009-04-17 06:23:12 +08:00
|
|
|
return Stream.EmitAbbrev(Abbrev);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
2011-07-15 15:25:21 +08:00
|
|
|
/// \brief Create an abbreviation for the SLocEntry that refers to a macro
|
|
|
|
/// expansion.
|
|
|
|
static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) {
|
2009-04-10 11:52:48 +08:00
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2011-07-15 15:25:21 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_EXPANSION_ENTRY));
|
2009-04-10 11:52:48 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Start location
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // End location
|
2009-04-16 02:05:10 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length
|
2009-04-17 06:23:12 +08:00
|
|
|
return Stream.EmitAbbrev(Abbrev);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
namespace {
|
|
|
|
// Trait used for the on-disk hash table of header search information.
|
|
|
|
class HeaderFileInfoTrait {
|
|
|
|
ASTWriter &Writer;
|
|
|
|
|
2011-07-28 12:50:02 +08:00
|
|
|
// Keep track of the framework names we've used during serialization.
|
|
|
|
SmallVector<char, 128> FrameworkStringData;
|
|
|
|
llvm::StringMap<unsigned> FrameworkNameOffset;
|
|
|
|
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
public:
|
2012-06-07 01:32:50 +08:00
|
|
|
HeaderFileInfoTrait(ASTWriter &Writer)
|
|
|
|
: Writer(Writer) { }
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
|
|
|
|
typedef const char *key_type;
|
|
|
|
typedef key_type key_type_ref;
|
|
|
|
|
|
|
|
typedef HeaderFileInfo data_type;
|
|
|
|
typedef const data_type &data_type_ref;
|
|
|
|
|
|
|
|
static unsigned ComputeHash(const char *path) {
|
|
|
|
// The hash is based only on the filename portion of the key, so that the
|
|
|
|
// reader can match based on filenames when symlinking or excess path
|
|
|
|
// elements ("foo/../", "../") change the form of the name. However,
|
|
|
|
// complete path is still the key.
|
|
|
|
return llvm::HashString(llvm::sys::path::filename(path));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
2011-07-23 18:55:15 +08:00
|
|
|
EmitKeyDataLength(raw_ostream& Out, const char *path,
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
data_type_ref Data) {
|
|
|
|
unsigned StrLen = strlen(path);
|
|
|
|
clang::io::Emit16(Out, StrLen);
|
2011-07-28 12:50:02 +08:00
|
|
|
unsigned DataLen = 1 + 2 + 4 + 4;
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
clang::io::Emit8(Out, DataLen);
|
|
|
|
return std::make_pair(StrLen + 1, DataLen);
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
Out.write(path, KeyLen);
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void EmitData(raw_ostream &Out, key_type_ref,
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
data_type_ref Data, unsigned DataLen) {
|
|
|
|
using namespace clang::io;
|
|
|
|
uint64_t Start = Out.tell(); (void)Start;
|
|
|
|
|
2011-07-28 12:50:02 +08:00
|
|
|
unsigned char Flags = (Data.isImport << 5)
|
|
|
|
| (Data.isPragmaOnce << 4)
|
|
|
|
| (Data.DirInfo << 2)
|
|
|
|
| (Data.Resolved << 1)
|
|
|
|
| Data.IndexHeaderMapHeader;
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
Emit8(Out, (uint8_t)Flags);
|
|
|
|
Emit16(Out, (uint16_t) Data.NumIncludes);
|
|
|
|
|
|
|
|
if (!Data.ControllingMacro)
|
|
|
|
Emit32(Out, (uint32_t)Data.ControllingMacroID);
|
|
|
|
else
|
|
|
|
Emit32(Out, (uint32_t)Writer.getIdentifierRef(Data.ControllingMacro));
|
2011-07-28 12:50:02 +08:00
|
|
|
|
|
|
|
unsigned Offset = 0;
|
|
|
|
if (!Data.Framework.empty()) {
|
|
|
|
// If this header refers into a framework, save the framework name.
|
|
|
|
llvm::StringMap<unsigned>::iterator Pos
|
|
|
|
= FrameworkNameOffset.find(Data.Framework);
|
|
|
|
if (Pos == FrameworkNameOffset.end()) {
|
|
|
|
Offset = FrameworkStringData.size() + 1;
|
|
|
|
FrameworkStringData.append(Data.Framework.begin(),
|
|
|
|
Data.Framework.end());
|
|
|
|
FrameworkStringData.push_back(0);
|
|
|
|
|
|
|
|
FrameworkNameOffset[Data.Framework] = Offset;
|
|
|
|
} else
|
|
|
|
Offset = Pos->second;
|
|
|
|
}
|
|
|
|
Emit32(Out, Offset);
|
|
|
|
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
assert(Out.tell() - Start == DataLen && "Wrong data length");
|
|
|
|
}
|
2011-07-28 12:50:02 +08:00
|
|
|
|
|
|
|
const char *strings_begin() const { return FrameworkStringData.begin(); }
|
|
|
|
const char *strings_end() const { return FrameworkStringData.end(); }
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
/// \brief Write the header search block for the list of files that
|
|
|
|
///
|
|
|
|
/// \param HS The header search structure to save.
|
2011-11-14 06:08:39 +08:00
|
|
|
void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<const FileEntry *, 16> FilesByUID;
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
|
|
|
|
|
|
|
|
if (FilesByUID.size() > HS.header_file_size())
|
|
|
|
FilesByUID.resize(HS.header_file_size());
|
|
|
|
|
2012-06-07 01:32:50 +08:00
|
|
|
HeaderFileInfoTrait GeneratorTrait(*this);
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<const char *, 4> SavedStrings;
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
unsigned NumHeaderSearchEntries = 0;
|
|
|
|
for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) {
|
|
|
|
const FileEntry *File = FilesByUID[UID];
|
|
|
|
if (!File)
|
|
|
|
continue;
|
|
|
|
|
2011-11-14 06:08:39 +08:00
|
|
|
// Use HeaderSearch's getFileInfo to make sure we get the HeaderFileInfo
|
|
|
|
// from the external source if it was not provided already.
|
|
|
|
const HeaderFileInfo &HFI = HS.getFileInfo(File);
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
if (HFI.External && Chain)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Turn the file name into an absolute path, if it isn't already.
|
|
|
|
const char *Filename = File->getName();
|
|
|
|
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
|
|
|
|
|
|
|
|
// If we performed any translation on the file name at all, we need to
|
|
|
|
// save this string, since the generator will refer to it later.
|
|
|
|
if (Filename != File->getName()) {
|
|
|
|
Filename = strdup(Filename);
|
|
|
|
SavedStrings.push_back(Filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
Generator.insert(Filename, HFI, GeneratorTrait);
|
|
|
|
++NumHeaderSearchEntries;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the on-disk hash table in a buffer.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<4096> TableData;
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
uint32_t BucketOffset;
|
|
|
|
{
|
|
|
|
llvm::raw_svector_ostream Out(TableData);
|
|
|
|
// Make sure that no bucket is at offset 0
|
|
|
|
clang::io::Emit32(Out, 0);
|
|
|
|
BucketOffset = Generator.Emit(Out, GeneratorTrait);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a blob abbreviation
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
2011-07-28 12:50:02 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned TableAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
2011-07-28 12:50:02 +08:00
|
|
|
// Write the header search table
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(HEADER_SEARCH_TABLE);
|
|
|
|
Record.push_back(BucketOffset);
|
|
|
|
Record.push_back(NumHeaderSearchEntries);
|
2011-07-28 12:50:02 +08:00
|
|
|
Record.push_back(TableData.size());
|
|
|
|
TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end());
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData.str());
|
|
|
|
|
|
|
|
// Free all of the strings we had to duplicate.
|
|
|
|
for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I)
|
|
|
|
free((void*)SavedStrings[I]);
|
|
|
|
}
|
|
|
|
|
2009-04-10 11:52:48 +08:00
|
|
|
/// \brief Writes the block containing the serialized form of the
|
|
|
|
/// source manager.
|
|
|
|
///
|
|
|
|
/// TODO: We should probably use an on-disk hash table (stored in a
|
|
|
|
/// blob), indexed based on the file name, so that we only create
|
|
|
|
/// entries for files that we actually need. In the common case (no
|
|
|
|
/// errors), we probably won't have to create file entries for any of
|
|
|
|
/// the files in the AST.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
|
2009-07-07 08:12:59 +08:00
|
|
|
const Preprocessor &PP,
|
2011-07-23 00:35:34 +08:00
|
|
|
StringRef isysroot) {
|
2009-04-27 14:38:32 +08:00
|
|
|
RecordData Record;
|
|
|
|
|
2009-04-11 01:16:57 +08:00
|
|
|
// Enter the source manager block.
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EnterSubblock(SOURCE_MANAGER_BLOCK_ID, 3);
|
2009-04-10 11:52:48 +08:00
|
|
|
|
|
|
|
// Abbreviations for the various kinds of source-location entries.
|
2009-04-28 03:03:22 +08:00
|
|
|
unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
|
|
|
|
unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
|
|
|
|
unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
|
2011-07-15 15:25:21 +08:00
|
|
|
unsigned SLocExpansionAbbrv = CreateSLocExpansionAbbrev(Stream);
|
2009-04-27 14:38:32 +08:00
|
|
|
|
2009-04-10 11:52:48 +08:00
|
|
|
// Write out the source location entry table. We skip the first
|
|
|
|
// entry, which is always the same dummy entry.
|
2009-04-28 03:01:47 +08:00
|
|
|
std::vector<uint32_t> SLocEntryOffsets;
|
2009-04-27 14:38:32 +08:00
|
|
|
RecordData PreloadSLocs;
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1);
|
|
|
|
for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size();
|
2010-07-23 01:01:13 +08:00
|
|
|
I != N; ++I) {
|
2009-10-17 06:46:09 +08:00
|
|
|
// Get this source location entry.
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
|
2012-10-03 05:09:17 +08:00
|
|
|
FileID FID = FileID::get(I);
|
|
|
|
assert(&SourceMgr.getSLocEntry(FID) == SLoc);
|
2010-03-14 15:06:50 +08:00
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
// Record the offset of this source-location entry.
|
|
|
|
SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
|
|
|
|
|
2009-04-10 11:52:48 +08:00
|
|
|
// Figure out which record code to use.
|
|
|
|
unsigned Code;
|
|
|
|
if (SLoc->isFile()) {
|
2011-11-17 04:05:18 +08:00
|
|
|
const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
|
|
|
|
if (Cache->OrigEntry) {
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = SM_SLOC_FILE_ENTRY;
|
2011-06-03 04:01:46 +08:00
|
|
|
} else
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = SM_SLOC_BUFFER_ENTRY;
|
2009-04-10 11:52:48 +08:00
|
|
|
} else
|
2011-07-15 15:25:21 +08:00
|
|
|
Code = SM_SLOC_EXPANSION_ENTRY;
|
2009-04-27 14:38:32 +08:00
|
|
|
Record.clear();
|
2009-04-10 11:52:48 +08:00
|
|
|
Record.push_back(Code);
|
|
|
|
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
// Starting offset of this entry within this module, so skip the dummy.
|
|
|
|
Record.push_back(SLoc->getOffset() - 2);
|
2009-04-10 11:52:48 +08:00
|
|
|
if (SLoc->isFile()) {
|
|
|
|
const SrcMgr::FileInfo &File = SLoc->getFile();
|
|
|
|
Record.push_back(File.getIncludeLoc().getRawEncoding());
|
|
|
|
Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding
|
2009-04-14 00:31:14 +08:00
|
|
|
Record.push_back(File.hasLineDirectives());
|
2009-04-10 11:52:48 +08:00
|
|
|
|
|
|
|
const SrcMgr::ContentCache *Content = File.getContentCache();
|
2011-03-05 09:03:53 +08:00
|
|
|
if (Content->OrigEntry) {
|
|
|
|
assert(Content->OrigEntry == Content->ContentsEntry &&
|
2011-11-17 04:05:18 +08:00
|
|
|
"Writing to AST an overridden file is not supported");
|
2011-03-05 09:03:53 +08:00
|
|
|
|
2012-10-23 02:42:04 +08:00
|
|
|
// The source location entry is a file. Emit input file ID.
|
|
|
|
assert(InputFileIDs[Content->OrigEntry] != 0 && "Missed file entry");
|
|
|
|
Record.push_back(InputFileIDs[Content->OrigEntry]);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-08-22 07:33:04 +08:00
|
|
|
Record.push_back(File.NumCreatedFIDs);
|
2011-10-29 06:54:21 +08:00
|
|
|
|
2012-10-03 05:09:17 +08:00
|
|
|
FileDeclIDsTy::iterator FDI = FileDeclIDs.find(FID);
|
2011-10-29 06:54:21 +08:00
|
|
|
if (FDI != FileDeclIDs.end()) {
|
|
|
|
Record.push_back(FDI->second->FirstDeclIndex);
|
|
|
|
Record.push_back(FDI->second->DeclIDs.size());
|
|
|
|
} else {
|
|
|
|
Record.push_back(0);
|
|
|
|
Record.push_back(0);
|
|
|
|
}
|
2011-11-17 04:05:18 +08:00
|
|
|
|
2012-10-23 02:42:04 +08:00
|
|
|
Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record);
|
2011-11-17 04:05:18 +08:00
|
|
|
|
|
|
|
if (Content->BufferOverridden) {
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(SM_SLOC_BUFFER_BLOB);
|
|
|
|
const llvm::MemoryBuffer *Buffer
|
|
|
|
= Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
|
|
|
|
Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
|
|
|
|
StringRef(Buffer->getBufferStart(),
|
|
|
|
Buffer->getBufferSize() + 1));
|
|
|
|
}
|
2009-04-10 11:52:48 +08:00
|
|
|
} else {
|
|
|
|
// The source location entry is a buffer. The blob associated
|
|
|
|
// with this entry contains the contents of the buffer.
|
|
|
|
|
|
|
|
// We add one to the size so that we capture the trailing NULL
|
|
|
|
// that is required by llvm::MemoryBuffer::getMemBuffer (on
|
|
|
|
// the reader side).
|
2010-03-16 08:35:39 +08:00
|
|
|
const llvm::MemoryBuffer *Buffer
|
2010-04-21 04:35:58 +08:00
|
|
|
= Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
|
2009-04-10 11:52:48 +08:00
|
|
|
const char *Name = Buffer->getBufferIdentifier();
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef(Name, strlen(Name) + 1));
|
2009-04-10 11:52:48 +08:00
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(SM_SLOC_BUFFER_BLOB);
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef(Buffer->getBufferStart(),
|
2009-08-24 17:31:37 +08:00
|
|
|
Buffer->getBufferSize() + 1));
|
2009-04-27 14:38:32 +08:00
|
|
|
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
if (strcmp(Name, "<built-in>") == 0) {
|
|
|
|
PreloadSLocs.push_back(SLocEntryOffsets.size());
|
|
|
|
}
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
} else {
|
2011-07-15 15:25:21 +08:00
|
|
|
// The source location entry is a macro expansion.
|
2011-07-26 12:56:51 +08:00
|
|
|
const SrcMgr::ExpansionInfo &Expansion = SLoc->getExpansion();
|
2011-07-26 12:41:47 +08:00
|
|
|
Record.push_back(Expansion.getSpellingLoc().getRawEncoding());
|
|
|
|
Record.push_back(Expansion.getExpansionLocStart().getRawEncoding());
|
2011-08-17 08:31:14 +08:00
|
|
|
Record.push_back(Expansion.isMacroArgExpansion() ? 0
|
|
|
|
: Expansion.getExpansionLocEnd().getRawEncoding());
|
2009-04-10 11:52:48 +08:00
|
|
|
|
2009-04-16 02:05:10 +08:00
|
|
|
// Compute the token length for this macro expansion.
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
unsigned NextOffset = SourceMgr.getNextLocalOffset();
|
2009-10-17 06:46:09 +08:00
|
|
|
if (I + 1 != N)
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
NextOffset = SourceMgr.getLocalSLocEntry(I + 1).getOffset();
|
2009-04-16 02:05:10 +08:00
|
|
|
Record.push_back(NextOffset - SLoc->getOffset() - 1);
|
2011-07-15 15:25:21 +08:00
|
|
|
Stream.EmitRecordWithAbbrev(SLocExpansionAbbrv, Record);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
Stream.ExitBlock();
|
2009-04-14 00:31:14 +08:00
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
if (SLocEntryOffsets.empty())
|
|
|
|
return;
|
2009-04-26 08:07:37 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// Write the source-location offsets table into the AST block. This
|
2009-04-27 14:38:32 +08:00
|
|
|
// table is used for lazily loading source-location information.
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS));
|
2009-04-27 14:38:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size
|
2009-04-27 14:38:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
|
|
|
|
unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(SOURCE_LOCATION_OFFSETS);
|
2009-04-27 14:38:32 +08:00
|
|
|
Record.push_back(SLocEntryOffsets.size());
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy
|
2011-04-25 01:44:50 +08:00
|
|
|
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets));
|
2009-04-27 14:38:32 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// Write the source location entry preloads array, telling the AST
|
2009-04-27 14:38:32 +08:00
|
|
|
// reader which source locations entries it should load eagerly.
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
|
|
|
|
// Write the line table. It depends on remapping working, so it must come
|
|
|
|
// after the source location offsets.
|
|
|
|
if (SourceMgr.hasLineTable()) {
|
|
|
|
LineTableInfo &LineTable = SourceMgr.getLineTable();
|
|
|
|
|
|
|
|
Record.clear();
|
|
|
|
// Emit the file names
|
|
|
|
Record.push_back(LineTable.getNumFilenames());
|
|
|
|
for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
|
|
|
|
// Emit the file name
|
|
|
|
const char *Filename = LineTable.getFilename(I);
|
|
|
|
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
|
|
|
|
unsigned FilenameLen = Filename? strlen(Filename) : 0;
|
|
|
|
Record.push_back(FilenameLen);
|
|
|
|
if (FilenameLen)
|
|
|
|
Record.insert(Record.end(), Filename, Filename + FilenameLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the line entries
|
|
|
|
for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
|
|
|
|
L != LEnd; ++L) {
|
|
|
|
// Only emit entries for local files.
|
2012-06-09 00:40:28 +08:00
|
|
|
if (L->first.ID < 0)
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Emit the file ID
|
2012-06-09 00:40:28 +08:00
|
|
|
Record.push_back(L->first.ID);
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
|
|
|
|
// Emit the line entries
|
|
|
|
Record.push_back(L->second.size());
|
|
|
|
for (std::vector<LineEntry>::iterator LE = L->second.begin(),
|
|
|
|
LEEnd = L->second.end();
|
|
|
|
LE != LEEnd; ++LE) {
|
|
|
|
Record.push_back(LE->FileOffset);
|
|
|
|
Record.push_back(LE->LineNo);
|
|
|
|
Record.push_back(LE->FilenameID);
|
|
|
|
Record.push_back((unsigned)LE->FileKind);
|
|
|
|
Record.push_back(LE->IncludeOffset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Stream.EmitRecord(SOURCE_MANAGER_LINE_TABLE, Record);
|
|
|
|
}
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Preprocessor Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-02-11 02:20:09 +08:00
|
|
|
static int compareMacroDefinitions(const void *XPtr, const void *YPtr) {
|
|
|
|
const std::pair<const IdentifierInfo *, MacroInfo *> &X =
|
|
|
|
*(const std::pair<const IdentifierInfo *, MacroInfo *>*)XPtr;
|
|
|
|
const std::pair<const IdentifierInfo *, MacroInfo *> &Y =
|
|
|
|
*(const std::pair<const IdentifierInfo *, MacroInfo *>*)YPtr;
|
|
|
|
return X.first->getName().compare(Y.first->getName());
|
|
|
|
}
|
|
|
|
|
2009-04-11 01:15:23 +08:00
|
|
|
/// \brief Writes the block containing the serialized form of the
|
|
|
|
/// preprocessor.
|
|
|
|
///
|
2011-09-02 01:04:32 +08:00
|
|
|
void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
|
2011-09-16 02:02:56 +08:00
|
|
|
PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
|
|
|
|
if (PPRec)
|
|
|
|
WritePreprocessorDetail(*PPRec);
|
|
|
|
|
2009-04-11 02:00:12 +08:00
|
|
|
RecordData Record;
|
|
|
|
|
2009-04-13 09:29:17 +08:00
|
|
|
// If the preprocessor __COUNTER__ value has been bumped, remember it.
|
|
|
|
if (PP.getCounterValue() != 0) {
|
|
|
|
Record.push_back(PP.getCounterValue());
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(PP_COUNTER_VALUE, Record);
|
2009-04-13 09:29:17 +08:00
|
|
|
Record.clear();
|
2009-04-26 08:07:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Enter the preprocessor block.
|
2010-10-21 06:00:55 +08:00
|
|
|
Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// If the AST file contains __DATE__ or __TIME__ emit a warning about this.
|
2009-04-26 08:07:37 +08:00
|
|
|
// FIXME: use diagnostics subsystem for localization etc.
|
|
|
|
if (PP.SawDateOrTime())
|
|
|
|
fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-10-21 06:00:55 +08:00
|
|
|
|
2009-04-11 02:00:12 +08:00
|
|
|
// Loop over all the macro definitions that are live at the end of the file,
|
|
|
|
// emitting each to the PP section.
|
2010-10-21 11:16:25 +08:00
|
|
|
|
2011-02-11 02:20:09 +08:00
|
|
|
// Construct the list of macro definitions that need to be serialized.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2>
|
2011-02-11 02:20:09 +08:00
|
|
|
MacrosToEmit;
|
|
|
|
llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen;
|
2012-09-26 01:18:14 +08:00
|
|
|
for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
|
2011-02-11 08:26:14 +08:00
|
|
|
E = PP.macro_end(Chain == 0);
|
2009-04-11 02:00:12 +08:00
|
|
|
I != E; ++I) {
|
2012-09-26 01:18:14 +08:00
|
|
|
if (!IsModule || I->second->isPublic()) {
|
|
|
|
MacroDefinitionsSeen.insert(I->first);
|
|
|
|
MacrosToEmit.push_back(std::make_pair(I->first, I->second));
|
2011-09-02 01:04:32 +08:00
|
|
|
}
|
2011-02-11 02:20:09 +08:00
|
|
|
}
|
2012-09-26 01:18:14 +08:00
|
|
|
|
2011-02-11 02:20:09 +08:00
|
|
|
// Sort the set of macro definitions that need to be serialized by the
|
|
|
|
// name of the macro, to provide a stable ordering.
|
2012-09-26 01:18:14 +08:00
|
|
|
llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(),
|
2011-02-11 02:20:09 +08:00
|
|
|
&compareMacroDefinitions);
|
2012-09-26 01:18:14 +08:00
|
|
|
|
2012-10-10 07:05:51 +08:00
|
|
|
/// \brief Offsets of each of the macros into the bitstream, indexed by
|
|
|
|
/// the local macro ID
|
|
|
|
///
|
|
|
|
/// For each identifier that is associated with a macro, this map
|
|
|
|
/// provides the offset into the bitstream where that macro is
|
|
|
|
/// defined.
|
|
|
|
std::vector<uint32_t> MacroOffsets;
|
|
|
|
|
2011-02-11 02:20:09 +08:00
|
|
|
for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) {
|
|
|
|
const IdentifierInfo *Name = MacrosToEmit[I].first;
|
2009-04-11 02:00:12 +08:00
|
|
|
|
2012-10-10 07:05:51 +08:00
|
|
|
for (MacroInfo *MI = MacrosToEmit[I].second; MI;
|
|
|
|
MI = MI->getPreviousDefinition()) {
|
|
|
|
MacroID ID = getMacroRef(MI);
|
|
|
|
if (!ID)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Skip macros from a AST file if we're chaining.
|
|
|
|
if (Chain && MI->isFromAST() && !MI->hasChangedAfterLoad())
|
|
|
|
continue;
|
2010-10-21 11:16:25 +08:00
|
|
|
|
2012-10-10 07:05:51 +08:00
|
|
|
if (ID < FirstMacroID) {
|
|
|
|
// This will have been dealt with via an update record.
|
|
|
|
assert(MacroUpdates.count(MI) > 0 && "Missing macro update");
|
2012-09-26 01:18:14 +08:00
|
|
|
continue;
|
2012-10-10 07:05:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Record the local offset of this macro.
|
|
|
|
unsigned Index = ID - FirstMacroID;
|
|
|
|
if (Index == MacroOffsets.size())
|
|
|
|
MacroOffsets.push_back(Stream.GetCurrentBitNo());
|
|
|
|
else {
|
|
|
|
if (Index > MacroOffsets.size())
|
|
|
|
MacroOffsets.resize(Index + 1);
|
|
|
|
|
|
|
|
MacroOffsets[Index] = Stream.GetCurrentBitNo();
|
|
|
|
}
|
2010-10-21 11:16:25 +08:00
|
|
|
|
2012-09-26 01:18:14 +08:00
|
|
|
AddIdentifierRef(Name, Record);
|
2012-10-10 07:05:51 +08:00
|
|
|
addMacroRef(MI, Record);
|
2012-10-11 08:46:49 +08:00
|
|
|
Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
|
2012-09-26 01:18:14 +08:00
|
|
|
AddSourceLocation(MI->getDefinitionLoc(), Record);
|
|
|
|
AddSourceLocation(MI->getUndefLoc(), Record);
|
|
|
|
Record.push_back(MI->isUsed());
|
|
|
|
Record.push_back(MI->isPublic());
|
|
|
|
AddSourceLocation(MI->getVisibilityLocation(), Record);
|
|
|
|
unsigned Code;
|
|
|
|
if (MI->isObjectLike()) {
|
|
|
|
Code = PP_MACRO_OBJECT_LIKE;
|
|
|
|
} else {
|
|
|
|
Code = PP_MACRO_FUNCTION_LIKE;
|
|
|
|
|
|
|
|
Record.push_back(MI->isC99Varargs());
|
|
|
|
Record.push_back(MI->isGNUVarargs());
|
|
|
|
Record.push_back(MI->getNumArgs());
|
|
|
|
for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
|
|
|
|
I != E; ++I)
|
|
|
|
AddIdentifierRef(*I, Record);
|
|
|
|
}
|
2009-04-11 01:16:57 +08:00
|
|
|
|
2012-09-26 01:18:14 +08:00
|
|
|
// If we have a detailed preprocessing record, record the macro definition
|
|
|
|
// ID that corresponds to this macro.
|
|
|
|
if (PPRec)
|
|
|
|
Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
|
|
|
|
|
|
|
|
Stream.EmitRecord(Code, Record);
|
2009-04-11 02:08:30 +08:00
|
|
|
Record.clear();
|
2012-09-26 01:18:14 +08:00
|
|
|
|
|
|
|
// Emit the tokens array.
|
|
|
|
for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
|
|
|
|
// Note that we know that the preprocessor does not have any annotation
|
|
|
|
// tokens in it because they are created by the parser, and thus can't
|
|
|
|
// be in a macro definition.
|
|
|
|
const Token &Tok = MI->getReplacementToken(TokNo);
|
|
|
|
|
|
|
|
Record.push_back(Tok.getLocation().getRawEncoding());
|
|
|
|
Record.push_back(Tok.getLength());
|
|
|
|
|
|
|
|
// FIXME: When reading literal tokens, reconstruct the literal pointer
|
|
|
|
// if it is needed.
|
|
|
|
AddIdentifierRef(Tok.getIdentifierInfo(), Record);
|
|
|
|
// FIXME: Should translate token kind to a stable encoding.
|
|
|
|
Record.push_back(Tok.getKind());
|
|
|
|
// FIXME: Should translate token flags to a stable encoding.
|
|
|
|
Record.push_back(Tok.getFlags());
|
|
|
|
|
|
|
|
Stream.EmitRecord(PP_TOKEN, Record);
|
|
|
|
Record.clear();
|
|
|
|
}
|
|
|
|
++NumMacros;
|
2009-04-11 02:08:30 +08:00
|
|
|
}
|
2009-04-11 02:00:12 +08:00
|
|
|
}
|
2011-02-09 05:58:10 +08:00
|
|
|
Stream.ExitBlock();
|
2012-10-10 07:05:51 +08:00
|
|
|
|
|
|
|
// Write the offsets table for macro IDs.
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
|
|
|
|
unsigned MacroOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(MACRO_OFFSET);
|
|
|
|
Record.push_back(MacroOffsets.size());
|
|
|
|
Record.push_back(FirstMacroID - NUM_PREDEF_MACRO_IDS);
|
|
|
|
Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record,
|
|
|
|
data(MacroOffsets));
|
2011-02-09 05:58:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
|
2011-09-20 04:40:42 +08:00
|
|
|
if (PPRec.local_begin() == PPRec.local_end())
|
2011-02-09 05:58:10 +08:00
|
|
|
return;
|
2011-09-16 02:02:56 +08:00
|
|
|
|
2011-09-20 04:40:25 +08:00
|
|
|
SmallVector<PPEntityOffset, 64> PreprocessedEntityOffsets;
|
2011-09-16 02:02:56 +08:00
|
|
|
|
2011-02-09 05:58:10 +08:00
|
|
|
// Enter the preprocessor block.
|
|
|
|
Stream.EnterSubblock(PREPROCESSOR_DETAIL_BLOCK_ID, 3);
|
2010-10-21 11:16:25 +08:00
|
|
|
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
// If the preprocessor has a preprocessing record, emit it.
|
|
|
|
unsigned NumPreprocessingRecords = 0;
|
2011-02-09 05:58:10 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
// Set up the abbreviation for
|
|
|
|
unsigned InclusionAbbrev = 0;
|
|
|
|
{
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind
|
2012-10-03 00:10:46 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // imported module
|
2011-02-09 05:58:10 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
InclusionAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
}
|
|
|
|
|
2011-08-05 02:56:47 +08:00
|
|
|
unsigned FirstPreprocessorEntityID
|
|
|
|
= (Chain ? PPRec.getNumLoadedPreprocessedEntities() : 0)
|
|
|
|
+ NUM_PREDEF_PP_ENTITY_IDS;
|
|
|
|
unsigned NextPreprocessorEntityID = FirstPreprocessorEntityID;
|
2011-02-09 05:58:10 +08:00
|
|
|
RecordData Record;
|
2011-09-20 04:40:42 +08:00
|
|
|
for (PreprocessingRecord::iterator E = PPRec.local_begin(),
|
|
|
|
EEnd = PPRec.local_end();
|
2011-08-05 01:06:18 +08:00
|
|
|
E != EEnd;
|
|
|
|
(void)++E, ++NumPreprocessingRecords, ++NextPreprocessorEntityID) {
|
2011-02-09 05:58:10 +08:00
|
|
|
Record.clear();
|
2010-10-21 11:16:25 +08:00
|
|
|
|
2011-09-20 04:40:25 +08:00
|
|
|
PreprocessedEntityOffsets.push_back(PPEntityOffset((*E)->getSourceRange(),
|
|
|
|
Stream.GetCurrentBitNo()));
|
2011-09-16 02:02:56 +08:00
|
|
|
|
2011-02-09 05:58:10 +08:00
|
|
|
if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
|
2011-09-16 02:02:56 +08:00
|
|
|
// Record this macro definition's ID.
|
|
|
|
MacroDefinitions[MD] = NextPreprocessorEntityID;
|
2011-02-09 05:58:10 +08:00
|
|
|
|
|
|
|
AddIdentifierRef(MD->getName(), Record);
|
|
|
|
Stream.EmitRecord(PPD_MACRO_DEFINITION, Record);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-07-14 16:20:46 +08:00
|
|
|
if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) {
|
2011-09-09 01:18:41 +08:00
|
|
|
Record.push_back(ME->isBuiltinMacro());
|
|
|
|
if (ME->isBuiltinMacro())
|
|
|
|
AddIdentifierRef(ME->getName(), Record);
|
|
|
|
else
|
2011-09-16 02:02:56 +08:00
|
|
|
Record.push_back(MacroDefinitions[ME->getDefinition()]);
|
2011-07-15 15:25:21 +08:00
|
|
|
Stream.EmitRecord(PPD_MACRO_EXPANSION, Record);
|
2011-02-09 05:58:10 +08:00
|
|
|
continue;
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
}
|
2010-10-21 11:16:25 +08:00
|
|
|
|
2011-02-09 05:58:10 +08:00
|
|
|
if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
|
|
|
|
Record.push_back(PPD_INCLUSION_DIRECTIVE);
|
|
|
|
Record.push_back(ID->getFileName().size());
|
|
|
|
Record.push_back(ID->wasInQuotes());
|
|
|
|
Record.push_back(static_cast<unsigned>(ID->getKind()));
|
2012-10-03 00:10:46 +08:00
|
|
|
Record.push_back(ID->importedModule());
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<64> Buffer;
|
2011-02-09 05:58:10 +08:00
|
|
|
Buffer += ID->getFileName();
|
2012-03-08 09:08:28 +08:00
|
|
|
// Check that the FileEntry is not null because it was not resolved and
|
|
|
|
// we create a PCH even with compiler errors.
|
|
|
|
if (ID->getFile())
|
|
|
|
Buffer += ID->getFile()->getName();
|
2011-02-09 05:58:10 +08:00
|
|
|
Stream.EmitRecordWithBlob(InclusionAbbrev, Record, Buffer);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("Unhandled PreprocessedEntity in ASTWriter");
|
|
|
|
}
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.ExitBlock();
|
2010-10-21 11:16:25 +08:00
|
|
|
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
// Write the offsets table for the preprocessing record.
|
|
|
|
if (NumPreprocessingRecords > 0) {
|
2011-09-16 02:02:56 +08:00
|
|
|
assert(PreprocessedEntityOffsets.size() == NumPreprocessingRecords);
|
|
|
|
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
// Write the offsets table for identifier IDs.
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2011-09-16 02:02:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS));
|
2011-08-05 02:56:47 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
2011-09-16 02:02:56 +08:00
|
|
|
unsigned PPEOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
2010-10-21 11:16:25 +08:00
|
|
|
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
Record.clear();
|
2011-09-16 02:02:56 +08:00
|
|
|
Record.push_back(PPD_ENTITIES_OFFSETS);
|
2011-08-05 02:56:47 +08:00
|
|
|
Record.push_back(FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS);
|
2011-09-16 02:02:56 +08:00
|
|
|
Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record,
|
|
|
|
data(PreprocessedEntityOffsets));
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
}
|
2009-04-11 01:15:23 +08:00
|
|
|
}
|
|
|
|
|
2011-12-06 09:10:29 +08:00
|
|
|
unsigned ASTWriter::getSubmoduleID(Module *Mod) {
|
|
|
|
llvm::DenseMap<Module *, unsigned>::iterator Known = SubmoduleIDs.find(Mod);
|
|
|
|
if (Known != SubmoduleIDs.end())
|
|
|
|
return Known->second;
|
|
|
|
|
|
|
|
return SubmoduleIDs[Mod] = NextSubmoduleID++;
|
|
|
|
}
|
|
|
|
|
2011-12-01 08:59:36 +08:00
|
|
|
/// \brief Compute the number of modules within the given tree (including the
|
|
|
|
/// given module).
|
|
|
|
static unsigned getNumberOfModules(Module *Mod) {
|
|
|
|
unsigned ChildModules = 0;
|
2012-01-05 07:32:19 +08:00
|
|
|
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
|
|
|
|
SubEnd = Mod->submodule_end();
|
2011-12-01 08:59:36 +08:00
|
|
|
Sub != SubEnd; ++Sub)
|
2012-01-05 07:32:19 +08:00
|
|
|
ChildModules += getNumberOfModules(*Sub);
|
2011-12-01 08:59:36 +08:00
|
|
|
|
|
|
|
return ChildModules + 1;
|
|
|
|
}
|
|
|
|
|
2011-12-01 07:21:26 +08:00
|
|
|
void ASTWriter::WriteSubmodules(Module *WritingModule) {
|
2011-12-06 00:35:23 +08:00
|
|
|
// Determine the dependencies of our module and each of it's submodules.
|
2011-12-06 00:33:54 +08:00
|
|
|
// FIXME: This feels like it belongs somewhere else, but there are no
|
|
|
|
// other consumers of this information.
|
|
|
|
SourceManager &SrcMgr = PP->getSourceManager();
|
|
|
|
ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap();
|
|
|
|
for (ASTContext::import_iterator I = Context->local_import_begin(),
|
|
|
|
IEnd = Context->local_import_end();
|
|
|
|
I != IEnd; ++I) {
|
|
|
|
if (Module *ImportedFrom
|
|
|
|
= ModMap.inferModuleFromLocation(FullSourceLoc(I->getLocation(),
|
|
|
|
SrcMgr))) {
|
|
|
|
ImportedFrom->Imports.push_back(I->getImportedModule());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-01 01:33:56 +08:00
|
|
|
// Enter the submodule description block.
|
|
|
|
Stream.EnterSubblock(SUBMODULE_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
|
|
|
|
|
|
|
|
// Write the abbreviations needed for the submodules block.
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
|
2011-12-06 09:10:29 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
|
2011-12-01 01:33:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
|
2012-01-28 03:52:33 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
|
2011-12-06 06:27:44 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
|
2011-12-01 01:33:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
|
|
|
|
unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
Abbrev = new BitCodeAbbrev();
|
2011-12-09 03:11:24 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_HEADER));
|
2011-12-01 01:33:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
|
|
|
|
unsigned UmbrellaAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
|
|
|
|
unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev);
|
2011-12-09 03:11:24 +08:00
|
|
|
|
2012-10-05 08:22:33 +08:00
|
|
|
Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TOPHEADER));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
|
|
|
|
unsigned TopHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
2011-12-09 03:11:24 +08:00
|
|
|
Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
|
|
|
|
unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
|
|
|
|
unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
2012-10-15 14:28:11 +08:00
|
|
|
Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXCLUDED_HEADER));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
|
|
|
|
unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
2011-12-01 08:59:36 +08:00
|
|
|
// Write the submodule metadata block.
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(getNumberOfModules(WritingModule));
|
|
|
|
Record.push_back(FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS);
|
|
|
|
Stream.EmitRecord(SUBMODULE_METADATA, Record);
|
|
|
|
|
2011-12-01 01:33:56 +08:00
|
|
|
// Write all of the submodules.
|
2011-12-01 07:21:26 +08:00
|
|
|
std::queue<Module *> Q;
|
2011-12-01 01:33:56 +08:00
|
|
|
Q.push(WritingModule);
|
|
|
|
while (!Q.empty()) {
|
2011-12-01 07:21:26 +08:00
|
|
|
Module *Mod = Q.front();
|
2011-12-01 01:33:56 +08:00
|
|
|
Q.pop();
|
2011-12-06 09:10:29 +08:00
|
|
|
unsigned ID = getSubmoduleID(Mod);
|
2011-12-01 01:33:56 +08:00
|
|
|
|
|
|
|
// Emit the definition of the block.
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(SUBMODULE_DEFINITION);
|
2011-12-06 09:10:29 +08:00
|
|
|
Record.push_back(ID);
|
2011-12-01 01:33:56 +08:00
|
|
|
if (Mod->Parent) {
|
|
|
|
assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?");
|
|
|
|
Record.push_back(SubmoduleIDs[Mod->Parent]);
|
|
|
|
} else {
|
|
|
|
Record.push_back(0);
|
|
|
|
}
|
|
|
|
Record.push_back(Mod->IsFramework);
|
|
|
|
Record.push_back(Mod->IsExplicit);
|
2012-01-28 03:52:33 +08:00
|
|
|
Record.push_back(Mod->IsSystem);
|
2011-12-06 06:27:44 +08:00
|
|
|
Record.push_back(Mod->InferSubmodules);
|
|
|
|
Record.push_back(Mod->InferExplicitSubmodules);
|
|
|
|
Record.push_back(Mod->InferExportWildcard);
|
2011-12-01 01:33:56 +08:00
|
|
|
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
|
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
// Emit the requirements.
|
|
|
|
for (unsigned I = 0, N = Mod->Requires.size(); I != N; ++I) {
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(SUBMODULE_REQUIRES);
|
|
|
|
Stream.EmitRecordWithBlob(RequiresAbbrev, Record,
|
|
|
|
Mod->Requires[I].data(),
|
|
|
|
Mod->Requires[I].size());
|
|
|
|
}
|
|
|
|
|
2011-12-01 01:33:56 +08:00
|
|
|
// Emit the umbrella header, if there is one.
|
2011-12-09 01:39:04 +08:00
|
|
|
if (const FileEntry *UmbrellaHeader = Mod->getUmbrellaHeader()) {
|
2011-12-01 01:33:56 +08:00
|
|
|
Record.clear();
|
2011-12-09 03:11:24 +08:00
|
|
|
Record.push_back(SUBMODULE_UMBRELLA_HEADER);
|
2011-12-01 01:33:56 +08:00
|
|
|
Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record,
|
2011-12-09 01:39:04 +08:00
|
|
|
UmbrellaHeader->getName());
|
2011-12-09 03:11:24 +08:00
|
|
|
} else if (const DirectoryEntry *UmbrellaDir = Mod->getUmbrellaDir()) {
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(SUBMODULE_UMBRELLA_DIR);
|
|
|
|
Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record,
|
|
|
|
UmbrellaDir->getName());
|
2011-12-01 01:33:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the headers.
|
|
|
|
for (unsigned I = 0, N = Mod->Headers.size(); I != N; ++I) {
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(SUBMODULE_HEADER);
|
|
|
|
Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
|
|
|
|
Mod->Headers[I]->getName());
|
|
|
|
}
|
2012-10-15 14:28:11 +08:00
|
|
|
// Emit the excluded headers.
|
|
|
|
for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) {
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(SUBMODULE_EXCLUDED_HEADER);
|
|
|
|
Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
|
|
|
|
Mod->ExcludedHeaders[I]->getName());
|
|
|
|
}
|
2012-10-05 08:22:33 +08:00
|
|
|
for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) {
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(SUBMODULE_TOPHEADER);
|
|
|
|
Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record,
|
|
|
|
Mod->TopHeaders[I]->getName());
|
|
|
|
}
|
2011-12-06 00:33:54 +08:00
|
|
|
|
|
|
|
// Emit the imports.
|
|
|
|
if (!Mod->Imports.empty()) {
|
|
|
|
Record.clear();
|
|
|
|
for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
|
2011-12-13 07:17:57 +08:00
|
|
|
unsigned ImportedID = getSubmoduleID(Mod->Imports[I]);
|
2011-12-06 00:33:54 +08:00
|
|
|
assert(ImportedID && "Unknown submodule!");
|
|
|
|
Record.push_back(ImportedID);
|
|
|
|
}
|
|
|
|
Stream.EmitRecord(SUBMODULE_IMPORTS, Record);
|
|
|
|
}
|
|
|
|
|
2011-12-03 02:58:38 +08:00
|
|
|
// Emit the exports.
|
|
|
|
if (!Mod->Exports.empty()) {
|
|
|
|
Record.clear();
|
|
|
|
for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
|
2011-12-13 07:17:57 +08:00
|
|
|
if (Module *Exported = Mod->Exports[I].getPointer()) {
|
|
|
|
unsigned ExportedID = SubmoduleIDs[Exported];
|
|
|
|
assert(ExportedID > 0 && "Unknown submodule ID?");
|
|
|
|
Record.push_back(ExportedID);
|
|
|
|
} else {
|
|
|
|
Record.push_back(0);
|
|
|
|
}
|
|
|
|
|
2011-12-03 02:58:38 +08:00
|
|
|
Record.push_back(Mod->Exports[I].getInt());
|
|
|
|
}
|
|
|
|
Stream.EmitRecord(SUBMODULE_EXPORTS, Record);
|
|
|
|
}
|
|
|
|
|
2011-12-01 01:33:56 +08:00
|
|
|
// Queue up the submodules of this module.
|
2012-01-05 07:32:19 +08:00
|
|
|
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
|
|
|
|
SubEnd = Mod->submodule_end();
|
2011-12-01 01:33:56 +08:00
|
|
|
Sub != SubEnd; ++Sub)
|
2012-01-05 07:32:19 +08:00
|
|
|
Q.push(*Sub);
|
2011-12-01 01:33:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Stream.ExitBlock();
|
2011-12-06 09:10:29 +08:00
|
|
|
|
|
|
|
assert((NextSubmoduleID - FirstSubmoduleID
|
|
|
|
== getNumberOfModules(WritingModule)) && "Wrong # of submodules");
|
2011-12-01 01:33:56 +08:00
|
|
|
}
|
|
|
|
|
2011-12-01 10:07:58 +08:00
|
|
|
serialization::SubmoduleID
|
|
|
|
ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
|
2011-12-06 09:10:29 +08:00
|
|
|
if (Loc.isInvalid() || !WritingModule)
|
2011-12-01 10:07:58 +08:00
|
|
|
return 0; // No submodule
|
2011-12-06 00:33:54 +08:00
|
|
|
|
|
|
|
// Find the module that owns this location.
|
2011-12-01 10:07:58 +08:00
|
|
|
ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap();
|
2011-12-06 00:33:54 +08:00
|
|
|
Module *OwningMod
|
|
|
|
= ModMap.inferModuleFromLocation(FullSourceLoc(Loc,PP->getSourceManager()));
|
2011-12-01 10:07:58 +08:00
|
|
|
if (!OwningMod)
|
|
|
|
return 0;
|
|
|
|
|
2011-12-06 09:10:29 +08:00
|
|
|
// Check whether this submodule is part of our own module.
|
|
|
|
if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(WritingModule))
|
2011-12-01 10:07:58 +08:00
|
|
|
return 0;
|
|
|
|
|
2011-12-06 09:10:29 +08:00
|
|
|
return getSubmoduleID(OwningMod);
|
2011-12-01 10:07:58 +08:00
|
|
|
}
|
|
|
|
|
2011-09-26 07:23:43 +08:00
|
|
|
void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
|
2010-11-06 06:10:18 +08:00
|
|
|
RecordData Record;
|
2011-09-26 07:23:43 +08:00
|
|
|
for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
|
2011-01-15 04:54:07 +08:00
|
|
|
I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end();
|
|
|
|
I != E; ++I) {
|
2011-09-26 07:23:43 +08:00
|
|
|
const DiagnosticsEngine::DiagStatePoint &point = *I;
|
2011-01-15 04:54:07 +08:00
|
|
|
if (point.Loc.isInvalid())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Record.push_back(point.Loc.getRawEncoding());
|
2011-09-29 09:42:25 +08:00
|
|
|
for (DiagnosticsEngine::DiagState::const_iterator
|
2011-01-15 04:54:07 +08:00
|
|
|
I = point.State->begin(), E = point.State->end(); I != E; ++I) {
|
2011-09-29 09:30:00 +08:00
|
|
|
if (I->second.isPragma()) {
|
|
|
|
Record.push_back(I->first);
|
|
|
|
Record.push_back(I->second.getMapping());
|
2011-01-15 04:54:07 +08:00
|
|
|
}
|
2010-11-06 06:10:18 +08:00
|
|
|
}
|
2011-01-15 04:54:07 +08:00
|
|
|
Record.push_back(-1); // mark the end of the diag/map pairs for this
|
|
|
|
// location.
|
2010-11-06 06:10:18 +08:00
|
|
|
}
|
|
|
|
|
2010-11-06 06:20:49 +08:00
|
|
|
if (!Record.empty())
|
2011-01-15 04:54:07 +08:00
|
|
|
Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record);
|
2010-11-06 06:10:18 +08:00
|
|
|
}
|
|
|
|
|
2011-03-07 02:41:18 +08:00
|
|
|
void ASTWriter::WriteCXXBaseSpecifiersOffsets() {
|
|
|
|
if (CXXBaseSpecifiersOffsets.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
|
|
|
|
// Create a blob abbreviation for the C++ base specifiers offsets.
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
2011-08-04 08:01:48 +08:00
|
|
|
// Write the base specifier offsets table.
|
2011-03-07 02:41:18 +08:00
|
|
|
Record.clear();
|
|
|
|
Record.push_back(CXX_BASE_SPECIFIER_OFFSETS);
|
|
|
|
Record.push_back(CXXBaseSpecifiersOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record,
|
2011-04-25 01:44:50 +08:00
|
|
|
data(CXXBaseSpecifiersOffsets));
|
2011-03-07 02:41:18 +08:00
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-04-11 01:15:23 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
/// \brief Write the representation of a type to the AST stream.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteType(QualType T) {
|
2010-08-21 00:04:04 +08:00
|
|
|
TypeIdx &Idx = TypeIdxs[T];
|
2010-08-21 00:03:59 +08:00
|
|
|
if (Idx.getIndex() == 0) // we haven't seen this type before.
|
|
|
|
Idx = TypeIdx(NextTypeID++);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-10-06 02:37:06 +08:00
|
|
|
assert(Idx.getIndex() >= FirstTypeID && "Re-writing a type from a prior AST");
|
2010-10-05 02:21:45 +08:00
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// Record the offset for this type.
|
2010-08-21 00:03:59 +08:00
|
|
|
unsigned Index = Idx.getIndex() - FirstTypeID;
|
2010-07-27 08:17:23 +08:00
|
|
|
if (TypeOffsets.size() == Index)
|
2009-04-17 06:23:12 +08:00
|
|
|
TypeOffsets.push_back(Stream.GetCurrentBitNo());
|
2010-07-27 08:17:23 +08:00
|
|
|
else if (TypeOffsets.size() < Index) {
|
|
|
|
TypeOffsets.resize(Index + 1);
|
|
|
|
TypeOffsets[Index] = Stream.GetCurrentBitNo();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
RecordData Record;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// Emit the type's representation.
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter W(*this, Record);
|
2009-09-25 03:53:00 +08:00
|
|
|
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (T.hasLocalNonFastQualifiers()) {
|
|
|
|
Qualifiers Qs = T.getLocalQualifiers();
|
|
|
|
AddTypeRef(T.getLocalUnqualifiedType(), Record);
|
2009-09-25 03:53:00 +08:00
|
|
|
Record.push_back(Qs.getAsOpaqueValue());
|
2010-08-19 07:57:32 +08:00
|
|
|
W.Code = TYPE_EXT_QUAL;
|
2009-09-25 03:53:00 +08:00
|
|
|
} else {
|
|
|
|
switch (T->getTypeClass()) {
|
|
|
|
// For all of the concrete, non-dependent types, call the
|
|
|
|
// appropriate visitor function.
|
2009-04-10 06:27:44 +08:00
|
|
|
#define TYPE(Class, Base) \
|
2010-01-20 10:03:14 +08:00
|
|
|
case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break;
|
2009-04-10 06:27:44 +08:00
|
|
|
#define ABSTRACT_TYPE(Class, Base)
|
|
|
|
#include "clang/AST/TypeNodes.def"
|
2009-09-25 03:53:00 +08:00
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the serialized record.
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(W.Code, Record);
|
2009-04-15 05:18:50 +08:00
|
|
|
|
|
|
|
// Flush any expressions that were written as part of this type.
|
2009-04-17 06:23:12 +08:00
|
|
|
FlushStmts();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Declaration Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
/// \brief Write the block containing all of the declaration IDs
|
|
|
|
/// lexically declared within the given DeclContext.
|
|
|
|
///
|
|
|
|
/// \returns the offset of the DECL_CONTEXT_LEXICAL block within the
|
|
|
|
/// bistream, or 0 if no block was written.
|
2010-08-19 07:56:21 +08:00
|
|
|
uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
|
2009-04-10 06:27:44 +08:00
|
|
|
DeclContext *DC) {
|
2009-06-30 10:36:12 +08:00
|
|
|
if (DC->decls_empty())
|
2009-04-10 06:27:44 +08:00
|
|
|
return 0;
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
uint64_t Offset = Stream.GetCurrentBitNo();
|
2009-04-10 06:27:44 +08:00
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(DECL_CONTEXT_LEXICAL);
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<KindDeclIDPair, 64> Decls;
|
2009-06-30 10:36:12 +08:00
|
|
|
for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
|
|
|
|
D != DEnd; ++D)
|
2010-10-15 04:14:34 +08:00
|
|
|
Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D)));
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2009-04-23 06:34:57 +08:00
|
|
|
++NumLexicalDeclContexts;
|
2011-04-25 01:44:50 +08:00
|
|
|
Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, data(Decls));
|
2009-04-10 06:27:44 +08:00
|
|
|
return Offset;
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteTypeDeclOffsets() {
|
2010-07-17 00:36:56 +08:00
|
|
|
using namespace llvm;
|
|
|
|
RecordData Record;
|
|
|
|
|
|
|
|
// Write the type offsets array
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET));
|
2010-07-17 00:36:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types
|
2011-08-03 00:26:37 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index
|
2010-07-17 00:36:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block
|
|
|
|
unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(TYPE_OFFSET);
|
2010-07-17 00:36:56 +08:00
|
|
|
Record.push_back(TypeOffsets.size());
|
2011-08-03 00:26:37 +08:00
|
|
|
Record.push_back(FirstTypeID - NUM_PREDEF_TYPE_IDS);
|
2011-04-25 01:44:50 +08:00
|
|
|
Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, data(TypeOffsets));
|
2010-07-17 00:36:56 +08:00
|
|
|
|
|
|
|
// Write the declaration offsets array
|
|
|
|
Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(DECL_OFFSET));
|
2010-07-17 00:36:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations
|
2011-08-03 23:48:04 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base decl ID
|
2010-07-17 00:36:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block
|
|
|
|
unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(DECL_OFFSET);
|
2010-07-17 00:36:56 +08:00
|
|
|
Record.push_back(DeclOffsets.size());
|
2011-08-04 00:05:40 +08:00
|
|
|
Record.push_back(FirstDeclID - NUM_PREDEF_DECL_IDS);
|
2011-04-25 01:44:50 +08:00
|
|
|
Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, data(DeclOffsets));
|
2010-07-17 00:36:56 +08:00
|
|
|
}
|
|
|
|
|
2011-10-29 06:54:21 +08:00
|
|
|
void ASTWriter::WriteFileDeclIDsMap() {
|
|
|
|
using namespace llvm;
|
|
|
|
RecordData Record;
|
|
|
|
|
|
|
|
// Join the vectors of DeclIDs from all files.
|
|
|
|
SmallVector<DeclID, 256> FileSortedIDs;
|
|
|
|
for (FileDeclIDsTy::iterator
|
|
|
|
FI = FileDeclIDs.begin(), FE = FileDeclIDs.end(); FI != FE; ++FI) {
|
|
|
|
DeclIDInFileInfo &Info = *FI->second;
|
|
|
|
Info.FirstDeclIndex = FileSortedIDs.size();
|
|
|
|
for (LocDeclIDsTy::iterator
|
|
|
|
DI = Info.DeclIDs.begin(), DE = Info.DeclIDs.end(); DI != DE; ++DI)
|
|
|
|
FileSortedIDs.push_back(DI->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS));
|
2012-10-03 05:09:13 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
2011-10-29 06:54:21 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
|
|
|
|
Record.push_back(FILE_SORTED_DECLS);
|
2012-10-03 05:09:13 +08:00
|
|
|
Record.push_back(FileSortedIDs.size());
|
2011-10-29 06:54:21 +08:00
|
|
|
Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileSortedIDs));
|
|
|
|
}
|
|
|
|
|
2012-06-20 08:34:58 +08:00
|
|
|
void ASTWriter::WriteComments() {
|
|
|
|
Stream.EnterSubblock(COMMENTS_BLOCK_ID, 3);
|
2012-07-07 02:19:34 +08:00
|
|
|
ArrayRef<RawComment *> RawComments = Context->Comments.getComments();
|
2012-06-20 08:34:58 +08:00
|
|
|
RecordData Record;
|
2012-07-07 02:19:34 +08:00
|
|
|
for (ArrayRef<RawComment *>::iterator I = RawComments.begin(),
|
|
|
|
E = RawComments.end();
|
2012-06-20 08:34:58 +08:00
|
|
|
I != E; ++I) {
|
|
|
|
Record.clear();
|
2012-07-07 02:19:34 +08:00
|
|
|
AddSourceRange((*I)->getSourceRange(), Record);
|
|
|
|
Record.push_back((*I)->getKind());
|
|
|
|
Record.push_back((*I)->isTrailingComment());
|
|
|
|
Record.push_back((*I)->isAlmostTrailingComment());
|
2012-06-20 08:34:58 +08:00
|
|
|
Stream.EmitRecord(COMMENTS_RAW_COMMENT, Record);
|
|
|
|
}
|
|
|
|
Stream.ExitBlock();
|
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Global Method Pool and Selector Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-25 05:10:55 +08:00
|
|
|
namespace {
|
|
|
|
// Trait used for the on-disk hash table used in the method pool.
|
2010-08-19 07:56:27 +08:00
|
|
|
class ASTMethodPoolTrait {
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter &Writer;
|
2009-04-25 05:10:55 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
typedef Selector key_type;
|
|
|
|
typedef key_type key_type_ref;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-05 01:20:04 +08:00
|
|
|
struct data_type {
|
2010-08-19 07:57:32 +08:00
|
|
|
SelectorID ID;
|
2010-08-05 01:20:04 +08:00
|
|
|
ObjCMethodList Instance, Factory;
|
|
|
|
};
|
2009-04-25 05:10:55 +08:00
|
|
|
typedef const data_type& data_type_ref;
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) { }
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-25 05:10:55 +08:00
|
|
|
static unsigned ComputeHash(Selector Sel) {
|
2010-08-21 00:03:52 +08:00
|
|
|
return serialization::ComputeHash(Sel);
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
2011-07-23 18:55:15 +08:00
|
|
|
EmitKeyDataLength(raw_ostream& Out, Selector Sel,
|
2009-04-25 05:10:55 +08:00
|
|
|
data_type_ref Methods) {
|
|
|
|
unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4);
|
|
|
|
clang::io::Emit16(Out, KeyLen);
|
2010-08-05 01:20:04 +08:00
|
|
|
unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts
|
|
|
|
for (const ObjCMethodList *Method = &Methods.Instance; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
DataLen += 4;
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Factory; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
DataLen += 4;
|
|
|
|
clang::io::Emit16(Out, DataLen);
|
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void EmitKey(raw_ostream& Out, Selector Sel, unsigned) {
|
2009-09-09 23:08:12 +08:00
|
|
|
uint64_t Start = Out.tell();
|
2009-04-26 01:48:32 +08:00
|
|
|
assert((Start >> 32) == 0 && "Selector key offset too large");
|
|
|
|
Writer.SetSelectorOffset(Sel, Start);
|
2009-04-25 05:10:55 +08:00
|
|
|
unsigned N = Sel.getNumArgs();
|
|
|
|
clang::io::Emit16(Out, N);
|
|
|
|
if (N == 0)
|
|
|
|
N = 1;
|
|
|
|
for (unsigned I = 0; I != N; ++I)
|
2009-09-09 23:08:12 +08:00
|
|
|
clang::io::Emit32(Out,
|
2009-04-25 05:10:55 +08:00
|
|
|
Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void EmitData(raw_ostream& Out, key_type_ref,
|
2009-04-25 05:49:02 +08:00
|
|
|
data_type_ref Methods, unsigned DataLen) {
|
|
|
|
uint64_t Start = Out.tell(); (void)Start;
|
2010-08-05 01:20:04 +08:00
|
|
|
clang::io::Emit32(Out, Methods.ID);
|
2009-04-25 05:10:55 +08:00
|
|
|
unsigned NumInstanceMethods = 0;
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Instance; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
++NumInstanceMethods;
|
|
|
|
|
|
|
|
unsigned NumFactoryMethods = 0;
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Factory; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
++NumFactoryMethods;
|
|
|
|
|
|
|
|
clang::io::Emit16(Out, NumInstanceMethods);
|
|
|
|
clang::io::Emit16(Out, NumFactoryMethods);
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Instance; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Factory; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
|
2009-04-25 05:49:02 +08:00
|
|
|
|
|
|
|
assert(Out.tell() - Start == DataLen && "Data length is wrong");
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2010-08-04 05:58:15 +08:00
|
|
|
/// \brief Write ObjC data: selectors and the method pool.
|
2009-04-25 05:10:55 +08:00
|
|
|
///
|
|
|
|
/// The method pool contains both instance and factory methods, stored
|
2010-08-04 05:58:15 +08:00
|
|
|
/// in an on-disk hash table indexed by the selector. The hash table also
|
|
|
|
/// contains an empty entry for every other selector known to Sema.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteSelectors(Sema &SemaRef) {
|
2009-04-25 05:10:55 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2010-08-04 05:58:15 +08:00
|
|
|
// Do we have to do anything at all?
|
2010-08-05 01:20:04 +08:00
|
|
|
if (SemaRef.MethodPool.empty() && SelectorIDs.empty())
|
2010-08-04 05:58:15 +08:00
|
|
|
return;
|
2010-08-05 02:21:41 +08:00
|
|
|
unsigned NumTableEntries = 0;
|
2010-08-04 05:58:15 +08:00
|
|
|
// Create and write out the blob that contains selectors and the method pool.
|
2009-04-25 05:10:55 +08:00
|
|
|
{
|
2010-08-19 07:56:27 +08:00
|
|
|
OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator;
|
2010-08-21 00:04:27 +08:00
|
|
|
ASTMethodPoolTrait Trait(*this);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-04 05:58:15 +08:00
|
|
|
// Create the on-disk hash table representation. We walk through every
|
|
|
|
// selector we've seen and look it up in the method pool.
|
2010-08-05 02:21:41 +08:00
|
|
|
SelectorOffsets.resize(NextSelectorID - FirstSelectorID);
|
2010-08-19 07:57:32 +08:00
|
|
|
for (llvm::DenseMap<Selector, SelectorID>::iterator
|
2010-08-05 01:20:04 +08:00
|
|
|
I = SelectorIDs.begin(), E = SelectorIDs.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
Selector S = I->first;
|
2010-08-04 05:58:15 +08:00
|
|
|
Sema::GlobalMethodPool::iterator F = SemaRef.MethodPool.find(S);
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTMethodPoolTrait::data_type Data = {
|
2010-08-05 01:20:04 +08:00
|
|
|
I->second,
|
|
|
|
ObjCMethodList(),
|
|
|
|
ObjCMethodList()
|
|
|
|
};
|
|
|
|
if (F != SemaRef.MethodPool.end()) {
|
|
|
|
Data.Instance = F->second.first;
|
|
|
|
Data.Factory = F->second.second;
|
|
|
|
}
|
2010-08-19 07:56:27 +08:00
|
|
|
// Only write this selector if it's not in an existing AST or something
|
2010-08-05 02:21:41 +08:00
|
|
|
// changed.
|
|
|
|
if (Chain && I->second < FirstSelectorID) {
|
|
|
|
// Selector already exists. Did it change?
|
|
|
|
bool changed = false;
|
|
|
|
for (ObjCMethodList *M = &Data.Instance; !changed && M && M->Method;
|
|
|
|
M = M->Next) {
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!M->Method->isFromASTFile())
|
2010-08-05 02:21:41 +08:00
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
for (ObjCMethodList *M = &Data.Factory; !changed && M && M->Method;
|
|
|
|
M = M->Next) {
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!M->Method->isFromASTFile())
|
2010-08-05 02:21:41 +08:00
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
if (!changed)
|
|
|
|
continue;
|
2010-08-05 05:22:45 +08:00
|
|
|
} else if (Data.Instance.Method || Data.Factory.Method) {
|
|
|
|
// A new method pool entry.
|
|
|
|
++NumTableEntries;
|
2010-08-05 02:21:41 +08:00
|
|
|
}
|
2010-08-21 00:04:27 +08:00
|
|
|
Generator.insert(S, Data, Trait);
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the on-disk hash table in a buffer.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<4096> MethodPool;
|
2009-04-25 05:10:55 +08:00
|
|
|
uint32_t BucketOffset;
|
|
|
|
{
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTMethodPoolTrait Trait(*this);
|
2009-04-25 05:10:55 +08:00
|
|
|
llvm::raw_svector_ostream Out(MethodPool);
|
|
|
|
// Make sure that no bucket is at offset 0
|
2009-04-25 05:49:02 +08:00
|
|
|
clang::io::Emit32(Out, 0);
|
2009-04-25 05:10:55 +08:00
|
|
|
BucketOffset = Generator.Emit(Out, Trait);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a blob abbreviation
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(METHOD_POOL));
|
2009-04-25 05:10:55 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
2009-04-26 01:48:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
2009-04-25 05:10:55 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
2009-04-26 01:48:32 +08:00
|
|
|
// Write the method pool
|
2009-04-25 05:10:55 +08:00
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(METHOD_POOL);
|
2009-04-25 05:10:55 +08:00
|
|
|
Record.push_back(BucketOffset);
|
2010-08-05 02:21:41 +08:00
|
|
|
Record.push_back(NumTableEntries);
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool.str());
|
2009-04-26 01:48:32 +08:00
|
|
|
|
|
|
|
// Create a blob abbreviation for the selector table offsets.
|
|
|
|
Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SELECTOR_OFFSETS));
|
2010-10-30 06:39:52 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
|
2011-08-04 07:28:44 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
|
2009-04-26 01:48:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
// Write the selector offsets table.
|
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(SELECTOR_OFFSETS);
|
2009-04-26 01:48:32 +08:00
|
|
|
Record.push_back(SelectorOffsets.size());
|
2011-08-04 07:28:44 +08:00
|
|
|
Record.push_back(FirstSelectorID - NUM_PREDEF_SELECTOR_IDS);
|
2009-04-26 01:48:32 +08:00
|
|
|
Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record,
|
2011-04-25 01:44:50 +08:00
|
|
|
data(SelectorOffsets));
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
/// \brief Write the selectors referenced in @selector expression into AST file.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteReferencedSelectorsPool(Sema &SemaRef) {
|
2010-07-24 03:11:11 +08:00
|
|
|
using namespace llvm;
|
|
|
|
if (SemaRef.ReferencedSelectors.empty())
|
|
|
|
return;
|
2010-08-05 04:40:17 +08:00
|
|
|
|
2010-07-24 03:11:11 +08:00
|
|
|
RecordData Record;
|
2010-08-05 04:40:17 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// Note: this writes out all references even for a dependent AST. But it is
|
2010-08-05 06:21:29 +08:00
|
|
|
// very tricky to fix, and given that @selector shouldn't really appear in
|
|
|
|
// headers, probably not worth it. It's not a correctness issue.
|
2010-07-24 03:11:11 +08:00
|
|
|
for (DenseMap<Selector, SourceLocation>::iterator S =
|
|
|
|
SemaRef.ReferencedSelectors.begin(),
|
|
|
|
E = SemaRef.ReferencedSelectors.end(); S != E; ++S) {
|
|
|
|
Selector Sel = (*S).first;
|
|
|
|
SourceLocation Loc = (*S).second;
|
|
|
|
AddSelectorRef(Sel, Record);
|
|
|
|
AddSourceLocation(Loc, Record);
|
|
|
|
}
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(REFERENCED_SELECTOR_POOL, Record);
|
2010-07-24 03:11:11 +08:00
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Identifier Table Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
namespace {
|
2010-08-19 07:56:27 +08:00
|
|
|
class ASTIdentifierTableTrait {
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter &Writer;
|
2009-04-22 07:56:24 +08:00
|
|
|
Preprocessor &PP;
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
IdentifierResolver &IdResolver;
|
2011-09-02 01:04:32 +08:00
|
|
|
bool IsModule;
|
|
|
|
|
2009-04-29 05:18:29 +08:00
|
|
|
/// \brief Determines whether this is an "interesting" identifier
|
|
|
|
/// that needs a full IdentifierInfo structure written into the hash
|
|
|
|
/// table.
|
2011-09-02 01:04:32 +08:00
|
|
|
bool isInterestingIdentifier(IdentifierInfo *II, MacroInfo *&Macro) {
|
|
|
|
if (II->isPoisoned() ||
|
|
|
|
II->isExtensionToken() ||
|
|
|
|
II->getObjCOrBuiltinID() ||
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
II->hasRevertedTokenIDToIdentifier() ||
|
2011-09-02 01:04:32 +08:00
|
|
|
II->getFETokenInfo<void>())
|
|
|
|
return true;
|
|
|
|
|
2012-09-26 01:18:14 +08:00
|
|
|
return hadMacroDefinition(II, Macro);
|
2011-09-15 06:14:14 +08:00
|
|
|
}
|
2012-09-26 01:18:14 +08:00
|
|
|
|
|
|
|
bool hadMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) {
|
|
|
|
if (!II->hadMacroDefinition())
|
2011-09-02 01:04:32 +08:00
|
|
|
return false;
|
2012-09-26 01:18:14 +08:00
|
|
|
|
|
|
|
if (Macro || (Macro = PP.getMacroInfoHistory(II)))
|
2011-10-17 23:32:29 +08:00
|
|
|
return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic());
|
2012-09-26 01:18:14 +08:00
|
|
|
|
|
|
|
return false;
|
2009-04-29 05:18:29 +08:00
|
|
|
}
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
public:
|
2011-09-02 01:04:32 +08:00
|
|
|
typedef IdentifierInfo* key_type;
|
2009-04-21 04:36:09 +08:00
|
|
|
typedef key_type key_type_ref;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
typedef IdentID data_type;
|
2009-04-21 04:36:09 +08:00
|
|
|
typedef data_type data_type_ref;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP,
|
|
|
|
IdentifierResolver &IdResolver, bool IsModule)
|
|
|
|
: Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule) { }
|
2009-04-21 04:36:09 +08:00
|
|
|
|
|
|
|
static unsigned ComputeHash(const IdentifierInfo* II) {
|
2009-10-18 07:52:28 +08:00
|
|
|
return llvm::HashString(II->getName());
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
|
2009-10-19 04:26:12 +08:00
|
|
|
unsigned KeyLen = II->getLength() + 1;
|
2009-04-29 05:18:29 +08:00
|
|
|
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
|
2011-09-15 06:14:14 +08:00
|
|
|
MacroInfo *Macro = 0;
|
2011-09-02 01:04:32 +08:00
|
|
|
if (isInterestingIdentifier(II, Macro)) {
|
2012-09-26 01:18:14 +08:00
|
|
|
DataLen += 2; // 2 bytes for builtin ID
|
|
|
|
DataLen += 2; // 2 bytes for flags
|
2012-10-11 08:46:49 +08:00
|
|
|
if (hadMacroDefinition(II, Macro)) {
|
|
|
|
for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) {
|
|
|
|
if (Writer.getMacroRef(M) != 0)
|
|
|
|
DataLen += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
DataLen += 4;
|
|
|
|
}
|
2012-09-26 01:18:14 +08:00
|
|
|
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
for (IdentifierResolver::iterator D = IdResolver.begin(II),
|
|
|
|
DEnd = IdResolver.end();
|
2009-04-29 05:18:29 +08:00
|
|
|
D != DEnd; ++D)
|
2010-08-19 07:57:32 +08:00
|
|
|
DataLen += sizeof(DeclID);
|
2009-04-29 05:18:29 +08:00
|
|
|
}
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
clang::io::Emit16(Out, DataLen);
|
2009-04-29 04:01:51 +08:00
|
|
|
// We emit the key length after the data length so that every
|
|
|
|
// string is preceded by a 16-bit length. This matches the PTH
|
|
|
|
// format for storing identifiers.
|
2009-04-26 05:04:17 +08:00
|
|
|
clang::io::Emit16(Out, KeyLen);
|
2009-04-21 04:36:09 +08:00
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void EmitKey(raw_ostream& Out, const IdentifierInfo* II,
|
2009-04-21 04:36:09 +08:00
|
|
|
unsigned KeyLen) {
|
|
|
|
// Record the location of the key data. This is used when generating
|
|
|
|
// the mapping from persistent IDs to strings.
|
|
|
|
Writer.SetIdentifierOffset(II, Out.tell());
|
2009-10-19 04:26:12 +08:00
|
|
|
Out.write(II->getNameStart(), KeyLen);
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-09-02 01:04:32 +08:00
|
|
|
void EmitData(raw_ostream& Out, IdentifierInfo* II,
|
2010-08-19 07:57:32 +08:00
|
|
|
IdentID ID, unsigned) {
|
2011-09-15 06:14:14 +08:00
|
|
|
MacroInfo *Macro = 0;
|
2011-09-02 01:04:32 +08:00
|
|
|
if (!isInterestingIdentifier(II, Macro)) {
|
2009-04-29 05:18:29 +08:00
|
|
|
clang::io::Emit32(Out, ID << 1);
|
|
|
|
return;
|
|
|
|
}
|
2009-04-29 05:32:13 +08:00
|
|
|
|
2009-04-29 05:18:29 +08:00
|
|
|
clang::io::Emit32(Out, (ID << 1) | 0x01);
|
2012-09-26 01:18:14 +08:00
|
|
|
uint32_t Bits = (uint32_t)II->getObjCOrBuiltinID();
|
|
|
|
assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
|
|
|
|
clang::io::Emit16(Out, Bits);
|
|
|
|
Bits = 0;
|
|
|
|
bool HadMacroDefinition = hadMacroDefinition(II, Macro);
|
|
|
|
Bits = (Bits << 1) | unsigned(HadMacroDefinition);
|
2009-12-19 04:58:47 +08:00
|
|
|
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
|
|
|
|
Bits = (Bits << 1) | unsigned(II->isPoisoned());
|
2010-08-12 06:55:12 +08:00
|
|
|
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
|
2009-12-19 04:58:47 +08:00
|
|
|
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
|
2009-04-29 05:32:13 +08:00
|
|
|
clang::io::Emit16(Out, Bits);
|
2009-04-21 04:36:09 +08:00
|
|
|
|
2012-09-26 01:18:14 +08:00
|
|
|
if (HadMacroDefinition) {
|
2012-10-11 08:46:49 +08:00
|
|
|
// Write all of the macro IDs associated with this identifier.
|
|
|
|
for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) {
|
|
|
|
if (MacroID ID = Writer.getMacroRef(M))
|
|
|
|
clang::io::Emit32(Out, ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
clang::io::Emit32(Out, 0);
|
2011-12-02 23:45:10 +08:00
|
|
|
}
|
2012-09-26 01:18:14 +08:00
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
// Emit the declaration IDs in reverse order, because the
|
|
|
|
// IdentifierResolver provides the declarations as they would be
|
|
|
|
// visible (e.g., the function "stat" would come before the struct
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
// "stat"), but the ASTReader adds declarations to the end of the list
|
|
|
|
// (so we need to see the struct "status" before the function "status").
|
2010-07-24 07:49:55 +08:00
|
|
|
// Only emit declarations that aren't from a chained PCH, though.
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
SmallVector<Decl *, 16> Decls(IdResolver.begin(II),
|
|
|
|
IdResolver.end());
|
2011-07-23 18:55:15 +08:00
|
|
|
for (SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(),
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
DEnd = Decls.rend();
|
2009-04-21 04:36:09 +08:00
|
|
|
D != DEnd; ++D)
|
2010-08-03 02:30:12 +08:00
|
|
|
clang::io::Emit32(Out, Writer.getDeclID(*D));
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
/// \brief Write the identifier table into the AST file.
|
2009-04-11 08:14:32 +08:00
|
|
|
///
|
|
|
|
/// 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.
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
|
|
|
|
IdentifierResolver &IdResolver,
|
|
|
|
bool IsModule) {
|
2009-04-11 08:14:32 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
// Create and write out the blob that contains the identifier
|
|
|
|
// strings.
|
|
|
|
{
|
2010-08-19 07:56:27 +08:00
|
|
|
OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-29 04:33:11 +08:00
|
|
|
// Look for any identifiers that were named while processing the
|
|
|
|
// headers, but are otherwise not needed. We add these to the hash
|
|
|
|
// table to enable checking of the predefines buffer in the case
|
2010-08-19 07:56:27 +08:00
|
|
|
// where the user adds new macro definitions when building the AST
|
2009-04-29 04:33:11 +08:00
|
|
|
// file.
|
|
|
|
for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
|
|
|
|
IDEnd = PP.getIdentifierTable().end();
|
|
|
|
ID != IDEnd; ++ID)
|
|
|
|
getIdentifierRef(ID->second);
|
|
|
|
|
2010-07-24 07:49:55 +08:00
|
|
|
// Create the on-disk hash table representation. We only store offsets
|
|
|
|
// for identifiers that appear here for the first time.
|
|
|
|
IdentifierOffsets.resize(NextIdentID - FirstIdentID);
|
2010-08-19 07:57:32 +08:00
|
|
|
for (llvm::DenseMap<const IdentifierInfo *, IdentID>::iterator
|
2009-04-11 08:14:32 +08:00
|
|
|
ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();
|
|
|
|
ID != IDEnd; ++ID) {
|
|
|
|
assert(ID->first && "NULL identifier in identifier table");
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
if (!Chain || !ID->first->isFromAST() ||
|
|
|
|
ID->first->hasChangedSinceDeserialization())
|
2011-09-02 01:04:32 +08:00
|
|
|
Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
|
|
|
|
Trait);
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
2009-04-11 08:14:32 +08:00
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
// Create the on-disk hash table in a buffer.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<4096> IdentifierTable;
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
uint32_t BucketOffset;
|
2009-04-21 04:36:09 +08:00
|
|
|
{
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule);
|
2009-04-21 04:36:09 +08:00
|
|
|
llvm::raw_svector_ostream Out(IdentifierTable);
|
2009-04-25 05:10:55 +08:00
|
|
|
// Make sure that no bucket is at offset 0
|
2009-04-25 05:49:02 +08:00
|
|
|
clang::io::Emit32(Out, 0);
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
BucketOffset = Generator.Emit(Out, Trait);
|
2009-04-11 08:14:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a blob abbreviation
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_TABLE));
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
2009-04-21 04:36:09 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
2009-04-17 06:23:12 +08:00
|
|
|
unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);
|
2009-04-11 08:14:32 +08:00
|
|
|
|
|
|
|
// Write the identifier table
|
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(IDENTIFIER_TABLE);
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
Record.push_back(BucketOffset);
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str());
|
2009-04-11 08:14:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write the offsets table for identifier IDs.
|
2009-04-26 03:10:14 +08:00
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET));
|
2009-04-26 03:10:14 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers
|
2011-08-04 05:49:18 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
|
2009-04-26 03:10:14 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(IDENTIFIER_OFFSET);
|
2009-04-26 03:10:14 +08:00
|
|
|
Record.push_back(IdentifierOffsets.size());
|
2011-08-04 05:49:18 +08:00
|
|
|
Record.push_back(FirstIdentID - NUM_PREDEF_IDENT_IDS);
|
2009-04-26 03:10:14 +08:00
|
|
|
Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record,
|
2011-04-25 01:44:50 +08:00
|
|
|
data(IdentifierOffsets));
|
2009-04-11 08:14:32 +08:00
|
|
|
}
|
|
|
|
|
2010-08-21 00:04:27 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DeclContext's Name Lookup Table Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// Trait used for the on-disk hash table used in the method pool.
|
|
|
|
class ASTDeclContextNameLookupTrait {
|
|
|
|
ASTWriter &Writer;
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef DeclarationName key_type;
|
|
|
|
typedef key_type key_type_ref;
|
|
|
|
|
|
|
|
typedef DeclContext::lookup_result data_type;
|
|
|
|
typedef const data_type& data_type_ref;
|
|
|
|
|
|
|
|
explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { }
|
|
|
|
|
|
|
|
unsigned ComputeHash(DeclarationName Name) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
ID.AddInteger(Name.getNameKind());
|
|
|
|
|
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
ID.AddString(Name.getAsIdentifierInfo()->getName());
|
|
|
|
break;
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
ID.AddInteger(serialization::ComputeHash(Name.getObjCSelector()));
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
ID.AddInteger(Name.getCXXOverloadedOperator());
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
ID.AddString(Name.getCXXLiteralIdentifier()->getName());
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ID.ComputeHash();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
2011-07-23 18:55:15 +08:00
|
|
|
EmitKeyDataLength(raw_ostream& Out, DeclarationName Name,
|
2010-08-21 00:04:27 +08:00
|
|
|
data_type_ref Lookup) {
|
|
|
|
unsigned KeyLen = 1;
|
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
KeyLen += 4;
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
KeyLen += 1;
|
|
|
|
break;
|
Change the hashing function for DeclContext lookup within an AST file
by eliminating the type ID from constructor, destructor, and
conversion function names. There are several reasons for this change:
- A given type (say, int*) isn't guaranteed to have a single, unique
type ID within a chain of PCH files. Hence, we could end up hashing
based on the wrong type ID, causing name lookup to fail.
- The mapping from types back to type IDs required one DenseMap
entry for every type that was ever deserialized, which was an
unacceptable cost to support just the name lookup of constructors,
destructors, and conversion functions. Plus, this mapping could
never actually work with chained or multiple PCH, based on the first
bullet.
Once we have eliminated the type from the hash function, these
problems go away, as does my horrible "reverse type remap" hack, which
was doomed from the start (see bullet #1 above) and far too
complicated.
However, note that removing the type from the hash function means that
all constructors, destructors, and conversion functions have the same
hash key, so I've updated the caller to double-check that the
declarations found have the appropriate name.
llvm-svn: 136708
2011-08-03 02:32:54 +08:00
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
2010-08-21 00:04:27 +08:00
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
clang::io::Emit16(Out, KeyLen);
|
|
|
|
|
|
|
|
// 2 bytes for num of decls and 4 for each DeclID.
|
|
|
|
unsigned DataLen = 2 + 4 * (Lookup.second - Lookup.first);
|
|
|
|
clang::io::Emit16(Out, DataLen);
|
|
|
|
|
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) {
|
2010-08-21 00:04:27 +08:00
|
|
|
using namespace clang::io;
|
|
|
|
|
|
|
|
Emit8(Out, Name.getNameKind());
|
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
Emit32(Out, Writer.getIdentifierRef(Name.getAsIdentifierInfo()));
|
2012-09-19 21:40:40 +08:00
|
|
|
return;
|
2010-08-21 00:04:27 +08:00
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector()));
|
2012-09-19 21:40:40 +08:00
|
|
|
return;
|
2010-08-21 00:04:27 +08:00
|
|
|
case DeclarationName::CXXOperatorName:
|
2012-09-19 21:40:40 +08:00
|
|
|
assert(Name.getCXXOverloadedOperator() < NUM_OVERLOADED_OPERATORS &&
|
|
|
|
"Invalid operator?");
|
2010-08-21 00:04:27 +08:00
|
|
|
Emit8(Out, Name.getCXXOverloadedOperator());
|
2012-09-19 21:40:40 +08:00
|
|
|
return;
|
2010-08-21 00:04:27 +08:00
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier()));
|
2012-09-19 21:40:40 +08:00
|
|
|
return;
|
Change the hashing function for DeclContext lookup within an AST file
by eliminating the type ID from constructor, destructor, and
conversion function names. There are several reasons for this change:
- A given type (say, int*) isn't guaranteed to have a single, unique
type ID within a chain of PCH files. Hence, we could end up hashing
based on the wrong type ID, causing name lookup to fail.
- The mapping from types back to type IDs required one DenseMap
entry for every type that was ever deserialized, which was an
unacceptable cost to support just the name lookup of constructors,
destructors, and conversion functions. Plus, this mapping could
never actually work with chained or multiple PCH, based on the first
bullet.
Once we have eliminated the type from the hash function, these
problems go away, as does my horrible "reverse type remap" hack, which
was doomed from the start (see bullet #1 above) and far too
complicated.
However, note that removing the type from the hash function means that
all constructors, destructors, and conversion functions have the same
hash key, so I've updated the caller to double-check that the
declarations found have the appropriate name.
llvm-svn: 136708
2011-08-03 02:32:54 +08:00
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
2010-08-21 00:04:27 +08:00
|
|
|
case DeclarationName::CXXUsingDirective:
|
2012-09-19 21:40:40 +08:00
|
|
|
return;
|
2010-08-21 00:04:27 +08:00
|
|
|
}
|
2012-09-19 21:40:40 +08:00
|
|
|
|
|
|
|
llvm_unreachable("Invalid name kind?");
|
2010-08-21 00:04:27 +08:00
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void EmitData(raw_ostream& Out, key_type_ref,
|
2010-08-21 00:04:27 +08:00
|
|
|
data_type Lookup, unsigned DataLen) {
|
|
|
|
uint64_t Start = Out.tell(); (void)Start;
|
|
|
|
clang::io::Emit16(Out, Lookup.second - Lookup.first);
|
|
|
|
for (; Lookup.first != Lookup.second; ++Lookup.first)
|
|
|
|
clang::io::Emit32(Out, Writer.GetDeclRef(*Lookup.first));
|
|
|
|
|
|
|
|
assert(Out.tell() - Start == DataLen && "Data length is wrong");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2010-08-21 00:04:35 +08:00
|
|
|
/// \brief Write the block containing all of the declaration IDs
|
|
|
|
/// visible from the given DeclContext.
|
|
|
|
///
|
|
|
|
/// \returns the offset of the DECL_CONTEXT_VISIBLE block within the
|
2010-08-24 08:50:09 +08:00
|
|
|
/// bitstream, or 0 if no block was written.
|
2010-08-21 00:04:35 +08:00
|
|
|
uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
|
|
|
|
DeclContext *DC) {
|
|
|
|
if (DC->getPrimaryContext() != DC)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Since there is no name lookup into functions or methods, don't bother to
|
|
|
|
// build a visible-declarations table for these entities.
|
|
|
|
if (DC->isFunctionOrMethod())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// If not in C++, we perform name lookup for the translation unit via the
|
|
|
|
// IdentifierInfo chains, don't bother to build a visible-declarations table.
|
|
|
|
// FIXME: In C++ we need the visible declarations in order to "see" the
|
|
|
|
// friend declarations, is there a way to do this without writing the table ?
|
2012-03-11 15:00:24 +08:00
|
|
|
if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus)
|
2010-08-21 00:04:35 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Serialize the contents of the mapping used for lookup. Note that,
|
|
|
|
// although we have two very different code paths, the serialized
|
|
|
|
// representation is the same for both cases: a declaration name,
|
|
|
|
// followed by a size, followed by references to the visible
|
|
|
|
// declarations that have that name.
|
|
|
|
uint64_t Offset = Stream.GetCurrentBitNo();
|
2012-03-16 14:12:59 +08:00
|
|
|
StoredDeclsMap *Map = DC->buildLookup();
|
2010-08-21 00:04:35 +08:00
|
|
|
if (!Map || Map->empty())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator;
|
|
|
|
ASTDeclContextNameLookupTrait Trait(*this);
|
|
|
|
|
|
|
|
// Create the on-disk hash table representation.
|
2011-08-31 04:49:19 +08:00
|
|
|
DeclarationName ConversionName;
|
|
|
|
llvm::SmallVector<NamedDecl *, 4> ConversionDecls;
|
2010-08-21 00:04:35 +08:00
|
|
|
for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
|
|
|
|
D != DEnd; ++D) {
|
|
|
|
DeclarationName Name = D->first;
|
|
|
|
DeclContext::lookup_result Result = D->second.getLookupResult();
|
2011-08-31 04:49:19 +08:00
|
|
|
if (Result.first != Result.second) {
|
|
|
|
if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
|
|
|
|
// Hash all conversion function names to the same name. The actual
|
|
|
|
// type information in conversion function name is not used in the
|
|
|
|
// key (since such type information is not stable across different
|
|
|
|
// modules), so the intended effect is to coalesce all of the conversion
|
|
|
|
// functions under a single key.
|
|
|
|
if (!ConversionName)
|
|
|
|
ConversionName = Name;
|
|
|
|
ConversionDecls.append(Result.first, Result.second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-08-31 03:43:23 +08:00
|
|
|
Generator.insert(Name, Result, Trait);
|
2011-08-31 04:49:19 +08:00
|
|
|
}
|
2010-08-21 00:04:35 +08:00
|
|
|
}
|
|
|
|
|
2011-08-31 04:49:19 +08:00
|
|
|
// Add the conversion functions
|
|
|
|
if (!ConversionDecls.empty()) {
|
|
|
|
Generator.insert(ConversionName,
|
|
|
|
DeclContext::lookup_result(ConversionDecls.begin(),
|
|
|
|
ConversionDecls.end()),
|
|
|
|
Trait);
|
|
|
|
}
|
|
|
|
|
2010-08-21 00:04:35 +08:00
|
|
|
// Create the on-disk hash table in a buffer.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<4096> LookupTable;
|
2010-08-21 00:04:35 +08:00
|
|
|
uint32_t BucketOffset;
|
|
|
|
{
|
|
|
|
llvm::raw_svector_ostream Out(LookupTable);
|
|
|
|
// Make sure that no bucket is at offset 0
|
|
|
|
clang::io::Emit32(Out, 0);
|
|
|
|
BucketOffset = Generator.Emit(Out, Trait);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the lookup table
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(DECL_CONTEXT_VISIBLE);
|
|
|
|
Record.push_back(BucketOffset);
|
|
|
|
Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record,
|
|
|
|
LookupTable.str());
|
|
|
|
|
|
|
|
Stream.EmitRecord(DECL_CONTEXT_VISIBLE, Record);
|
|
|
|
++NumVisibleDeclContexts;
|
|
|
|
return Offset;
|
|
|
|
}
|
|
|
|
|
2010-08-24 08:50:09 +08:00
|
|
|
/// \brief Write an UPDATE_VISIBLE block for the given context.
|
|
|
|
///
|
|
|
|
/// UPDATE_VISIBLE blocks contain the declarations that are added to an existing
|
|
|
|
/// DeclContext in a dependent AST file. As such, they only exist for the TU
|
2012-03-16 14:12:59 +08:00
|
|
|
/// (in C++), for namespaces, and for classes with forward-declared unscoped
|
|
|
|
/// enumeration members (in C++11).
|
2010-08-24 08:50:09 +08:00
|
|
|
void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
|
|
|
|
StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
|
|
|
|
if (!Map || Map->empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator;
|
|
|
|
ASTDeclContextNameLookupTrait Trait(*this);
|
|
|
|
|
|
|
|
// Create the hash table.
|
|
|
|
for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
|
|
|
|
D != DEnd; ++D) {
|
|
|
|
DeclarationName Name = D->first;
|
|
|
|
DeclContext::lookup_result Result = D->second.getLookupResult();
|
2010-08-24 08:50:16 +08:00
|
|
|
// For any name that appears in this table, the results are complete, i.e.
|
|
|
|
// they overwrite results from previous PCHs. Merging is always a mess.
|
2011-08-31 03:43:23 +08:00
|
|
|
if (Result.first != Result.second)
|
|
|
|
Generator.insert(Name, Result, Trait);
|
2010-08-24 08:50:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the on-disk hash table in a buffer.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<4096> LookupTable;
|
2010-08-24 08:50:09 +08:00
|
|
|
uint32_t BucketOffset;
|
|
|
|
{
|
|
|
|
llvm::raw_svector_ostream Out(LookupTable);
|
|
|
|
// Make sure that no bucket is at offset 0
|
|
|
|
clang::io::Emit32(Out, 0);
|
|
|
|
BucketOffset = Generator.Emit(Out, Trait);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the lookup table
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(UPDATE_VISIBLE);
|
|
|
|
Record.push_back(getDeclID(cast<Decl>(DC)));
|
|
|
|
Record.push_back(BucketOffset);
|
|
|
|
Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable.str());
|
|
|
|
}
|
|
|
|
|
2011-02-16 03:46:30 +08:00
|
|
|
/// \brief Write an FP_PRAGMA_OPTIONS block for the given FPOptions.
|
|
|
|
void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) {
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(Opts.fp_contract);
|
|
|
|
Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Write an OPENCL_EXTENSIONS block for the given OpenCLOptions.
|
|
|
|
void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!SemaRef.Context.getLangOpts().OpenCL)
|
2011-02-16 03:46:30 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
const OpenCLOptions &Opts = SemaRef.getOpenCLOptions();
|
|
|
|
RecordData Record;
|
|
|
|
#define OPENCLEXT(nm) Record.push_back(Opts.nm);
|
|
|
|
#include "clang/Basic/OpenCLExtensions.def"
|
|
|
|
Stream.EmitRecord(OPENCL_EXTENSIONS, Record);
|
|
|
|
}
|
|
|
|
|
2012-01-16 00:58:34 +08:00
|
|
|
void ASTWriter::WriteRedeclarations() {
|
|
|
|
RecordData LocalRedeclChains;
|
|
|
|
SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap;
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) {
|
|
|
|
Decl *First = Redeclarations[I];
|
|
|
|
assert(First->getPreviousDecl() == 0 && "Not the first declaration?");
|
|
|
|
|
|
|
|
Decl *MostRecent = First->getMostRecentDecl();
|
|
|
|
|
|
|
|
// If we only have a single declaration, there is no point in storing
|
|
|
|
// a redeclaration chain.
|
|
|
|
if (First == MostRecent)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
unsigned Offset = LocalRedeclChains.size();
|
|
|
|
unsigned Size = 0;
|
|
|
|
LocalRedeclChains.push_back(0); // Placeholder for the size.
|
|
|
|
|
|
|
|
// Collect the set of local redeclarations of this declaration.
|
|
|
|
for (Decl *Prev = MostRecent; Prev != First;
|
|
|
|
Prev = Prev->getPreviousDecl()) {
|
|
|
|
if (!Prev->isFromASTFile()) {
|
|
|
|
AddDeclRef(Prev, LocalRedeclChains);
|
|
|
|
++Size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LocalRedeclChains[Offset] = Size;
|
|
|
|
|
|
|
|
// Reverse the set of local redeclarations, so that we store them in
|
|
|
|
// order (since we found them in reverse order).
|
|
|
|
std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end());
|
|
|
|
|
|
|
|
// Add the mapping from the first ID to the set of local declarations.
|
|
|
|
LocalRedeclarationsInfo Info = { getDeclID(First), Offset };
|
|
|
|
LocalRedeclsMap.push_back(Info);
|
|
|
|
|
|
|
|
assert(N == Redeclarations.size() &&
|
|
|
|
"Deserialized a declaration we shouldn't have");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LocalRedeclChains.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Sort the local redeclarations map by the first declaration ID,
|
|
|
|
// since the reader will be performing binary searches on this information.
|
|
|
|
llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end());
|
|
|
|
|
|
|
|
// Emit the local redeclarations map.
|
|
|
|
using namespace llvm;
|
|
|
|
llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS_MAP));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(LOCAL_REDECLARATIONS_MAP);
|
|
|
|
Record.push_back(LocalRedeclsMap.size());
|
|
|
|
Stream.EmitRecordWithBlob(AbbrevID, Record,
|
|
|
|
reinterpret_cast<char*>(LocalRedeclsMap.data()),
|
|
|
|
LocalRedeclsMap.size() * sizeof(LocalRedeclarationsInfo));
|
|
|
|
|
|
|
|
// Emit the redeclaration chains.
|
|
|
|
Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedeclChains);
|
|
|
|
}
|
|
|
|
|
2012-01-27 09:47:08 +08:00
|
|
|
void ASTWriter::WriteObjCCategories() {
|
|
|
|
llvm::SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
|
|
|
|
RecordData Categories;
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = ObjCClassesWithCategories.size(); I != N; ++I) {
|
|
|
|
unsigned Size = 0;
|
|
|
|
unsigned StartIndex = Categories.size();
|
|
|
|
|
|
|
|
ObjCInterfaceDecl *Class = ObjCClassesWithCategories[I];
|
|
|
|
|
|
|
|
// Allocate space for the size.
|
|
|
|
Categories.push_back(0);
|
|
|
|
|
|
|
|
// Add the categories.
|
|
|
|
for (ObjCCategoryDecl *Cat = Class->getCategoryList();
|
|
|
|
Cat; Cat = Cat->getNextClassCategory(), ++Size) {
|
|
|
|
assert(getDeclID(Cat) != 0 && "Bogus category");
|
|
|
|
AddDeclRef(Cat, Categories);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the size.
|
|
|
|
Categories[StartIndex] = Size;
|
|
|
|
|
|
|
|
// Record this interface -> category map.
|
|
|
|
ObjCCategoriesInfo CatInfo = { getDeclID(Class), StartIndex };
|
|
|
|
CategoriesMap.push_back(CatInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort the categories map by the definition ID, since the reader will be
|
|
|
|
// performing binary searches on this information.
|
|
|
|
llvm::array_pod_sort(CategoriesMap.begin(), CategoriesMap.end());
|
|
|
|
|
|
|
|
// Emit the categories map.
|
|
|
|
using namespace llvm;
|
|
|
|
llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(OBJC_CATEGORIES_MAP));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(OBJC_CATEGORIES_MAP);
|
|
|
|
Record.push_back(CategoriesMap.size());
|
|
|
|
Stream.EmitRecordWithBlob(AbbrevID, Record,
|
|
|
|
reinterpret_cast<char*>(CategoriesMap.data()),
|
|
|
|
CategoriesMap.size() * sizeof(ObjCCategoriesInfo));
|
|
|
|
|
|
|
|
// Emit the category lists.
|
|
|
|
Stream.EmitRecord(OBJC_CATEGORIES, Categories);
|
|
|
|
}
|
|
|
|
|
2011-12-23 05:40:42 +08:00
|
|
|
void ASTWriter::WriteMergedDecls() {
|
|
|
|
if (!Chain || Chain->MergedDecls.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
for (ASTReader::MergedDeclsMap::iterator I = Chain->MergedDecls.begin(),
|
|
|
|
IEnd = Chain->MergedDecls.end();
|
|
|
|
I != IEnd; ++I) {
|
2012-01-06 06:27:05 +08:00
|
|
|
DeclID CanonID = I->first->isFromASTFile()? I->first->getGlobalID()
|
2011-12-23 05:40:42 +08:00
|
|
|
: getDeclID(I->first);
|
|
|
|
assert(CanonID && "Merged declaration not known?");
|
|
|
|
|
|
|
|
Record.push_back(CanonID);
|
|
|
|
Record.push_back(I->second.size());
|
|
|
|
Record.append(I->second.begin(), I->second.end());
|
|
|
|
}
|
|
|
|
Stream.EmitRecord(MERGED_DECLARATIONS, Record);
|
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// General Serialization Routines
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-16 05:30:51 +08:00
|
|
|
/// \brief Write a record containing the given attributes.
|
2012-07-09 18:04:07 +08:00
|
|
|
void ASTWriter::WriteAttributes(ArrayRef<const Attr*> Attrs,
|
|
|
|
RecordDataImpl &Record) {
|
2010-10-19 03:20:11 +08:00
|
|
|
Record.push_back(Attrs.size());
|
2012-07-09 18:04:07 +08:00
|
|
|
for (ArrayRef<const Attr *>::iterator i = Attrs.begin(),
|
|
|
|
e = Attrs.end(); i != e; ++i){
|
|
|
|
const Attr *A = *i;
|
2010-08-19 07:23:40 +08:00
|
|
|
Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs
|
2011-09-14 00:05:58 +08:00
|
|
|
AddSourceRange(A->getRange(), Record);
|
2009-04-16 05:30:51 +08:00
|
|
|
|
2010-08-19 07:23:40 +08:00
|
|
|
#include "clang/Serialization/AttrPCHWrite.inc"
|
2009-05-21 01:41:43 +08:00
|
|
|
|
2009-04-16 05:30:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {
|
2009-04-16 05:30:51 +08:00
|
|
|
Record.push_back(Str.size());
|
|
|
|
Record.insert(Record.end(), Str.begin(), Str.end());
|
|
|
|
}
|
|
|
|
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
void ASTWriter::AddVersionTuple(const VersionTuple &Version,
|
|
|
|
RecordDataImpl &Record) {
|
|
|
|
Record.push_back(Version.getMajor());
|
|
|
|
if (llvm::Optional<unsigned> Minor = Version.getMinor())
|
|
|
|
Record.push_back(*Minor + 1);
|
|
|
|
else
|
|
|
|
Record.push_back(0);
|
|
|
|
if (llvm::Optional<unsigned> Subminor = Version.getSubminor())
|
|
|
|
Record.push_back(*Subminor + 1);
|
|
|
|
else
|
|
|
|
Record.push_back(0);
|
|
|
|
}
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
/// \brief Note that the identifier II occurs at the given offset
|
|
|
|
/// within the identifier table.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) {
|
2010-08-19 07:57:32 +08:00
|
|
|
IdentID ID = IdentifierIDs[II];
|
2010-08-19 07:56:27 +08:00
|
|
|
// Only store offsets new to this AST file. Other identifier names are looked
|
2010-07-24 07:49:55 +08:00
|
|
|
// up earlier in the chain and thus don't need an offset.
|
|
|
|
if (ID >= FirstIdentID)
|
|
|
|
IdentifierOffsets[ID - FirstIdentID] = Offset;
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
|
|
|
|
2009-04-26 01:48:32 +08:00
|
|
|
/// \brief Note that the selector Sel occurs at the given offset
|
|
|
|
/// within the method pool/selector table.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
|
2009-04-26 01:48:32 +08:00
|
|
|
unsigned ID = SelectorIDs[Sel];
|
|
|
|
assert(ID && "Unknown selector");
|
2010-08-05 02:21:41 +08:00
|
|
|
// Don't record offsets for selectors that are also available in a different
|
|
|
|
// file.
|
|
|
|
if (ID < FirstSelectorID)
|
|
|
|
return;
|
|
|
|
SelectorOffsets[ID - FirstSelectorID] = Offset;
|
2009-04-26 01:48:32 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
|
2011-12-06 09:10:29 +08:00
|
|
|
: Stream(Stream), Context(0), PP(0), Chain(0), WritingModule(0),
|
2012-07-03 03:19:01 +08:00
|
|
|
WritingAST(false), DoneWritingDeclsAndTypes(false),
|
|
|
|
ASTHasCompilerErrors(false),
|
2011-08-04 00:05:40 +08:00
|
|
|
FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
|
2010-08-19 07:57:32 +08:00
|
|
|
FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
|
2012-10-10 07:05:51 +08:00
|
|
|
FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
|
|
|
|
FirstMacroID(NUM_PREDEF_MACRO_IDS), NextMacroID(FirstMacroID),
|
2011-12-01 08:59:36 +08:00
|
|
|
FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS),
|
|
|
|
NextSubmoduleID(FirstSubmoduleID),
|
2011-08-04 07:28:44 +08:00
|
|
|
FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
|
2010-10-03 03:29:26 +08:00
|
|
|
CollectedStmts(&StmtsToEmit),
|
2010-08-05 02:21:41 +08:00
|
|
|
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
|
2011-06-03 10:27:19 +08:00
|
|
|
NumVisibleDeclContexts(0),
|
2011-08-04 08:01:48 +08:00
|
|
|
NextCXXBaseSpecifiersID(1),
|
2011-06-04 07:11:16 +08:00
|
|
|
DeclParmVarAbbrev(0), DeclContextLexicalAbbrev(0),
|
2011-06-03 10:27:19 +08:00
|
|
|
DeclContextVisibleLookupAbbrev(0), UpdateVisibleAbbrev(0),
|
|
|
|
DeclRefExprAbbrev(0), CharacterLiteralAbbrev(0),
|
|
|
|
DeclRecordAbbrev(0), IntegerLiteralAbbrev(0),
|
2011-06-04 07:11:16 +08:00
|
|
|
DeclTypedefAbbrev(0),
|
|
|
|
DeclVarAbbrev(0), DeclFieldAbbrev(0),
|
|
|
|
DeclEnumAbbrev(0), DeclObjCIvarAbbrev(0)
|
2010-10-30 06:39:52 +08:00
|
|
|
{
|
2010-07-15 07:45:08 +08:00
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2011-10-29 06:54:21 +08:00
|
|
|
ASTWriter::~ASTWriter() {
|
|
|
|
for (FileDeclIDsTy::iterator
|
|
|
|
I = FileDeclIDs.begin(), E = FileDeclIDs.end(); I != E; ++I)
|
|
|
|
delete I->second;
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
2011-02-16 01:54:22 +08:00
|
|
|
const std::string &OutputFile,
|
2012-03-07 09:51:17 +08:00
|
|
|
Module *WritingModule, StringRef isysroot,
|
|
|
|
bool hasErrors) {
|
2011-09-17 08:05:03 +08:00
|
|
|
WritingAST = true;
|
|
|
|
|
2012-03-07 09:51:17 +08:00
|
|
|
ASTHasCompilerErrors = hasErrors;
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// Emit the file header.
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.Emit((unsigned)'C', 8);
|
|
|
|
Stream.Emit((unsigned)'P', 8);
|
|
|
|
Stream.Emit((unsigned)'C', 8);
|
|
|
|
Stream.Emit((unsigned)'H', 8);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-27 06:26:21 +08:00
|
|
|
WriteBlockInfoBlock();
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2011-08-09 23:13:55 +08:00
|
|
|
Context = &SemaRef.Context;
|
2011-12-01 10:07:58 +08:00
|
|
|
PP = &SemaRef.PP;
|
2011-12-06 09:10:29 +08:00
|
|
|
this->WritingModule = WritingModule;
|
2011-11-30 12:39:39 +08:00
|
|
|
WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, WritingModule);
|
2011-08-09 23:13:55 +08:00
|
|
|
Context = 0;
|
2011-12-01 10:07:58 +08:00
|
|
|
PP = 0;
|
2011-12-06 09:10:29 +08:00
|
|
|
this->WritingModule = 0;
|
2011-09-17 08:05:03 +08:00
|
|
|
|
|
|
|
WritingAST = false;
|
2010-07-13 06:02:52 +08:00
|
|
|
}
|
|
|
|
|
2011-07-28 05:45:57 +08:00
|
|
|
template<typename Vector>
|
|
|
|
static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
|
|
|
|
ASTWriter::RecordData &Record) {
|
|
|
|
for (typename Vector::iterator I = Vec.begin(0, true), E = Vec.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
Writer.AddDeclRef(*I, Record);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
2011-07-23 00:35:34 +08:00
|
|
|
StringRef isysroot,
|
2011-11-30 12:39:39 +08:00
|
|
|
const std::string &OutputFile,
|
2011-12-01 07:21:26 +08:00
|
|
|
Module *WritingModule) {
|
2010-07-13 06:02:52 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2011-12-02 06:20:10 +08:00
|
|
|
// Make sure that the AST reader knows to finalize itself.
|
|
|
|
if (Chain)
|
|
|
|
Chain->finalizeForWriting();
|
|
|
|
|
2010-07-13 06:02:52 +08:00
|
|
|
ASTContext &Context = SemaRef.Context;
|
|
|
|
Preprocessor &PP = SemaRef.PP;
|
|
|
|
|
2011-08-12 08:15:20 +08:00
|
|
|
// Set up predefined declaration IDs.
|
|
|
|
DeclIDs[Context.getTranslationUnitDecl()] = PREDEF_DECL_TRANSLATION_UNIT_ID;
|
2011-08-12 13:46:01 +08:00
|
|
|
if (Context.ObjCIdDecl)
|
|
|
|
DeclIDs[Context.ObjCIdDecl] = PREDEF_DECL_OBJC_ID_ID;
|
2011-08-12 14:17:30 +08:00
|
|
|
if (Context.ObjCSelDecl)
|
|
|
|
DeclIDs[Context.ObjCSelDecl] = PREDEF_DECL_OBJC_SEL_ID;
|
2011-08-12 13:59:41 +08:00
|
|
|
if (Context.ObjCClassDecl)
|
|
|
|
DeclIDs[Context.ObjCClassDecl] = PREDEF_DECL_OBJC_CLASS_ID;
|
2012-01-18 02:09:05 +08:00
|
|
|
if (Context.ObjCProtocolClassDecl)
|
|
|
|
DeclIDs[Context.ObjCProtocolClassDecl] = PREDEF_DECL_OBJC_PROTOCOL_ID;
|
2011-08-12 14:49:56 +08:00
|
|
|
if (Context.Int128Decl)
|
|
|
|
DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID;
|
|
|
|
if (Context.UInt128Decl)
|
|
|
|
DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID;
|
2011-09-08 09:46:34 +08:00
|
|
|
if (Context.ObjCInstanceTypeDecl)
|
|
|
|
DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID;
|
2012-06-16 11:34:49 +08:00
|
|
|
if (Context.BuiltinVaListDecl)
|
|
|
|
DeclIDs[Context.getBuiltinVaListDecl()] = PREDEF_DECL_BUILTIN_VA_LIST_ID;
|
|
|
|
|
2011-08-12 09:39:19 +08:00
|
|
|
if (!Chain) {
|
|
|
|
// Make sure that we emit IdentifierInfos (and any attached
|
|
|
|
// declarations) for builtins. We don't need to do this when we're
|
|
|
|
// emitting chained PCH files, because all of the builtins will be
|
|
|
|
// in the original PCH file.
|
|
|
|
// FIXME: Modules won't like this at all.
|
2009-04-23 02:49:13 +08:00
|
|
|
IdentifierTable &Table = PP.getIdentifierTable();
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<const char *, 32> BuiltinNames;
|
2009-04-23 02:49:13 +08:00
|
|
|
Context.BuiltinInfo.GetBuiltinNames(BuiltinNames,
|
2012-03-11 15:00:24 +08:00
|
|
|
Context.getLangOpts().NoBuiltin);
|
2009-04-23 02:49:13 +08:00
|
|
|
for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I)
|
|
|
|
getIdentifierRef(&Table.get(BuiltinNames[I]));
|
|
|
|
}
|
|
|
|
|
Make the loading of information attached to an IdentifierInfo from an
AST file more lazy, so that we don't eagerly load that information for
all known identifiers each time a new AST file is loaded. The eager
reloading made some sense in the context of precompiled headers, since
very few identifiers were defined before PCH load time. With modules,
however, a huge amount of code can get parsed before we see an
@import, so laziness becomes important here.
The approach taken to make this information lazy is fairly simple:
when we load a new AST file, we mark all of the existing identifiers
as being out-of-date. Whenever we want to access information that may
come from an AST (e.g., whether the identifier has a macro definition,
or what top-level declarations have that name), we check the
out-of-date bit and, if it's set, ask the AST reader to update the
IdentifierInfo from the AST files. The update is a merge, and we now
take care to merge declarations before/after imports with declarations
from multiple imports.
The results of this optimization are fairly dramatic. On a small
application that brings in 14 non-trivial modules, this takes modules
from being > 3x slower than a "perfect" PCH file down to 30% slower
for a full rebuild. A partial rebuild (where the PCH file or modules
can be re-used) is down to 7% slower. Making the PCH file just a
little imperfect (e.g., adding two smallish modules used by a bunch of
.m files that aren't in the PCH file) tips the scales in favor of the
modules approach, with 24% faster partial rebuilds.
This is just a first step; the lazy scheme could possibly be improved
by adding versioning, so we don't search into modules we already
searched. Moreover, we'll need similar lazy schemes for all of the
other lookup data structures, such as DeclContexts.
llvm-svn: 143100
2011-10-27 17:33:13 +08:00
|
|
|
// If there are any out-of-date identifiers, bring them up to date.
|
|
|
|
if (ExternalPreprocessorSource *ExtSource = PP.getExternalSource()) {
|
|
|
|
for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
|
|
|
|
IDEnd = PP.getIdentifierTable().end();
|
|
|
|
ID != IDEnd; ++ID)
|
|
|
|
if (ID->second->isOutOfDate())
|
|
|
|
ExtSource->updateOutOfDateIdentifier(*ID->second);
|
|
|
|
}
|
|
|
|
|
2009-09-09 02:19:27 +08:00
|
|
|
// Build a record containing all of the tentative definitions in this file, in
|
2010-02-01 06:27:38 +08:00
|
|
|
// TentativeDefinitions order. Generally, this record will be empty for
|
2009-09-09 02:19:27 +08:00
|
|
|
// headers.
|
2009-04-23 06:02:47 +08:00
|
|
|
RecordData TentativeDefinitions;
|
2011-07-28 05:45:57 +08:00
|
|
|
AddLazyVectorDecls(*this, SemaRef.TentativeDefinitions, TentativeDefinitions);
|
2011-07-28 04:58:46 +08:00
|
|
|
|
2010-08-14 02:42:17 +08:00
|
|
|
// Build a record containing all of the file scoped decls in this file.
|
|
|
|
RecordData UnusedFileScopedDecls;
|
2011-07-28 05:45:57 +08:00
|
|
|
AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
|
|
|
|
UnusedFileScopedDecls);
|
2010-08-06 02:21:25 +08:00
|
|
|
|
2011-08-12 09:39:19 +08:00
|
|
|
// Build a record containing all of the delegating constructors we still need
|
|
|
|
// to resolve.
|
2011-05-05 07:29:54 +08:00
|
|
|
RecordData DelegatingCtorDecls;
|
2011-07-28 05:57:17 +08:00
|
|
|
AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
|
2011-05-05 07:29:54 +08:00
|
|
|
|
2011-08-12 09:39:19 +08:00
|
|
|
// Write the set of weak, undeclared identifiers. We always write the
|
|
|
|
// entire table, since later PCH files in a PCH chain are only interested in
|
|
|
|
// the results at the end of the chain.
|
2010-08-05 17:48:08 +08:00
|
|
|
RecordData WeakUndeclaredIdentifiers;
|
|
|
|
if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
|
2011-07-29 02:09:57 +08:00
|
|
|
for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator
|
2010-08-05 17:48:08 +08:00
|
|
|
I = SemaRef.WeakUndeclaredIdentifiers.begin(),
|
|
|
|
E = SemaRef.WeakUndeclaredIdentifiers.end(); I != E; ++I) {
|
|
|
|
AddIdentifierRef(I->first, WeakUndeclaredIdentifiers);
|
|
|
|
AddIdentifierRef(I->second.getAlias(), WeakUndeclaredIdentifiers);
|
|
|
|
AddSourceLocation(I->second.getLocation(), WeakUndeclaredIdentifiers);
|
|
|
|
WeakUndeclaredIdentifiers.push_back(I->second.getUsed());
|
|
|
|
}
|
|
|
|
}
|
2010-03-14 15:06:50 +08:00
|
|
|
|
2009-04-23 06:18:58 +08:00
|
|
|
// Build a record containing all of the locally-scoped external
|
|
|
|
// declarations in this header file. Generally, this record will be
|
|
|
|
// empty.
|
|
|
|
RecordData LocallyScopedExternalDecls;
|
2010-08-19 07:56:27 +08:00
|
|
|
// FIXME: This is filling in the AST file in densemap order which is
|
2009-09-09 02:19:27 +08:00
|
|
|
// nondeterminstic!
|
2009-09-09 23:08:12 +08:00
|
|
|
for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
|
2009-04-23 06:18:58 +08:00
|
|
|
TD = SemaRef.LocallyScopedExternalDecls.begin(),
|
|
|
|
TDEnd = SemaRef.LocallyScopedExternalDecls.end();
|
2011-07-28 22:20:37 +08:00
|
|
|
TD != TDEnd; ++TD) {
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!TD->second->isFromASTFile())
|
2011-07-28 22:20:37 +08:00
|
|
|
AddDeclRef(TD->second, LocallyScopedExternalDecls);
|
|
|
|
}
|
|
|
|
|
2009-04-28 04:06:05 +08:00
|
|
|
// Build a record containing all of the ext_vector declarations.
|
|
|
|
RecordData ExtVectorDecls;
|
2011-07-28 08:39:29 +08:00
|
|
|
AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls);
|
2009-04-28 04:06:05 +08:00
|
|
|
|
2010-07-06 23:37:04 +08:00
|
|
|
// Build a record containing all of the VTable uses information.
|
|
|
|
RecordData VTableUses;
|
2010-08-04 01:29:52 +08:00
|
|
|
if (!SemaRef.VTableUses.empty()) {
|
|
|
|
for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) {
|
|
|
|
AddDeclRef(SemaRef.VTableUses[I].first, VTableUses);
|
|
|
|
AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses);
|
|
|
|
VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]);
|
|
|
|
}
|
2010-07-06 23:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build a record containing all of dynamic classes declarations.
|
|
|
|
RecordData DynamicClasses;
|
2011-07-28 08:53:40 +08:00
|
|
|
AddLazyVectorDecls(*this, SemaRef.DynamicClasses, DynamicClasses);
|
2010-07-06 23:37:04 +08:00
|
|
|
|
2010-08-05 17:48:16 +08:00
|
|
|
// Build a record containing all of pending implicit instantiations.
|
2010-08-25 16:44:16 +08:00
|
|
|
RecordData PendingInstantiations;
|
2010-08-05 17:48:16 +08:00
|
|
|
for (std::deque<Sema::PendingImplicitInstantiation>::iterator
|
2010-08-25 16:44:16 +08:00
|
|
|
I = SemaRef.PendingInstantiations.begin(),
|
|
|
|
N = SemaRef.PendingInstantiations.end(); I != N; ++I) {
|
|
|
|
AddDeclRef(I->first, PendingInstantiations);
|
|
|
|
AddSourceLocation(I->second, PendingInstantiations);
|
2010-08-05 17:48:16 +08:00
|
|
|
}
|
|
|
|
assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&
|
|
|
|
"There are local ones at end of translation unit!");
|
|
|
|
|
2010-08-02 15:14:54 +08:00
|
|
|
// Build a record containing some declaration references.
|
|
|
|
RecordData SemaDeclRefs;
|
|
|
|
if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) {
|
|
|
|
AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs);
|
|
|
|
AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs);
|
|
|
|
}
|
|
|
|
|
2011-02-10 05:04:32 +08:00
|
|
|
RecordData CUDASpecialDeclRefs;
|
|
|
|
if (Context.getcudaConfigureCallDecl()) {
|
|
|
|
AddDeclRef(Context.getcudaConfigureCallDecl(), CUDASpecialDeclRefs);
|
|
|
|
}
|
|
|
|
|
2011-06-29 00:20:02 +08:00
|
|
|
// Build a record containing all of the known namespaces.
|
|
|
|
RecordData KnownNamespaces;
|
|
|
|
for (llvm::DenseMap<NamespaceDecl*, bool>::iterator
|
|
|
|
I = SemaRef.KnownNamespaces.begin(),
|
|
|
|
IEnd = SemaRef.KnownNamespaces.end();
|
|
|
|
I != IEnd; ++I) {
|
|
|
|
if (!I->second)
|
|
|
|
AddDeclRef(I->first, KnownNamespaces);
|
|
|
|
}
|
2012-10-18 13:31:06 +08:00
|
|
|
|
|
|
|
// Write the control block
|
2012-10-25 00:50:34 +08:00
|
|
|
WriteControlBlock(PP, Context, isysroot, OutputFile);
|
2012-10-18 13:31:06 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// Write the remaining AST contents.
|
2009-04-18 13:55:16 +08:00
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EnterSubblock(AST_BLOCK_ID, 5);
|
2011-07-23 00:35:34 +08:00
|
|
|
if (StatCalls && isysroot.empty())
|
2010-07-13 07:48:14 +08:00
|
|
|
WriteStatCache(*StatCalls);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-08-12 09:39:19 +08:00
|
|
|
// Create a lexical update block containing all of the declarations in the
|
|
|
|
// translation unit that do not come from other AST files.
|
2011-08-12 08:15:20 +08:00
|
|
|
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
|
|
|
|
SmallVector<KindDeclIDPair, 64> NewGlobalDecls;
|
|
|
|
for (DeclContext::decl_iterator I = TU->noload_decls_begin(),
|
2011-08-12 09:39:19 +08:00
|
|
|
E = TU->noload_decls_end();
|
2011-08-12 08:15:20 +08:00
|
|
|
I != E; ++I) {
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!(*I)->isFromASTFile())
|
2011-08-12 08:15:20 +08:00
|
|
|
NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I)));
|
|
|
|
}
|
2011-08-12 09:39:19 +08:00
|
|
|
|
2011-08-12 08:15:20 +08:00
|
|
|
llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL));
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(Abv);
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(TU_UPDATE_LEXICAL);
|
|
|
|
Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record,
|
|
|
|
data(NewGlobalDecls));
|
|
|
|
|
2011-08-12 09:39:19 +08:00
|
|
|
// And a visible updates block for the translation unit.
|
2011-08-12 08:15:20 +08:00
|
|
|
Abv = new llvm::BitCodeAbbrev();
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE));
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 32));
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
|
|
|
|
UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv);
|
|
|
|
WriteDeclContextVisibleUpdate(TU);
|
|
|
|
|
2011-08-12 09:39:19 +08:00
|
|
|
// If the translation unit has an anonymous namespace, and we don't already
|
|
|
|
// have an update block for it, write it as an update block.
|
2011-08-12 08:15:20 +08:00
|
|
|
if (NamespaceDecl *NS = TU->getAnonymousNamespace()) {
|
|
|
|
ASTWriter::UpdateRecord &Record = DeclUpdates[TU];
|
2011-08-12 09:39:19 +08:00
|
|
|
if (Record.empty()) {
|
|
|
|
Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE);
|
2011-09-17 08:05:03 +08:00
|
|
|
Record.push_back(reinterpret_cast<uint64_t>(NS));
|
2011-08-12 09:39:19 +08:00
|
|
|
}
|
2011-08-12 08:15:20 +08:00
|
|
|
}
|
2012-07-03 03:19:01 +08:00
|
|
|
|
|
|
|
// Make sure visible decls, added to DeclContexts previously loaded from
|
|
|
|
// an AST file, are registered for serialization.
|
|
|
|
for (SmallVector<const Decl *, 16>::iterator
|
|
|
|
I = UpdatingVisibleDecls.begin(),
|
|
|
|
E = UpdatingVisibleDecls.end(); I != E; ++I) {
|
|
|
|
GetDeclRef(*I);
|
|
|
|
}
|
|
|
|
|
2011-11-14 12:52:24 +08:00
|
|
|
// Resolve any declaration pointers within the declaration updates block.
|
2011-09-17 08:05:03 +08:00
|
|
|
ResolveDeclUpdatesBlocks();
|
|
|
|
|
2011-08-12 09:39:19 +08:00
|
|
|
// Form the record of special types.
|
|
|
|
RecordData SpecialTypes;
|
|
|
|
AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes);
|
|
|
|
AddTypeRef(Context.getFILEType(), SpecialTypes);
|
|
|
|
AddTypeRef(Context.getjmp_bufType(), SpecialTypes);
|
|
|
|
AddTypeRef(Context.getsigjmp_bufType(), SpecialTypes);
|
|
|
|
AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes);
|
|
|
|
AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes);
|
|
|
|
AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes);
|
2011-11-14 05:51:09 +08:00
|
|
|
AddTypeRef(Context.getucontext_tType(), SpecialTypes);
|
2011-12-01 10:07:58 +08:00
|
|
|
|
2009-04-26 11:49:13 +08:00
|
|
|
// Keep writing types and declarations until all types and
|
|
|
|
// declarations have been written.
|
2011-06-03 10:27:19 +08:00
|
|
|
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
|
2009-10-17 08:13:19 +08:00
|
|
|
WriteDeclsBlockAbbrevs();
|
2011-08-12 09:39:19 +08:00
|
|
|
for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(),
|
|
|
|
E = DeclsToRewrite.end();
|
|
|
|
I != E; ++I)
|
|
|
|
DeclTypesToEmit.push(const_cast<Decl*>(*I));
|
2009-10-17 08:13:19 +08:00
|
|
|
while (!DeclTypesToEmit.empty()) {
|
|
|
|
DeclOrType DOT = DeclTypesToEmit.front();
|
|
|
|
DeclTypesToEmit.pop();
|
|
|
|
if (DOT.isType())
|
|
|
|
WriteType(DOT.getType());
|
|
|
|
else
|
|
|
|
WriteDecl(Context, DOT.getDecl());
|
|
|
|
}
|
|
|
|
Stream.ExitBlock();
|
2010-03-14 15:06:50 +08:00
|
|
|
|
2012-07-03 03:19:01 +08:00
|
|
|
DoneWritingDeclsAndTypes = true;
|
|
|
|
|
2011-10-29 06:54:21 +08:00
|
|
|
WriteFileDeclIDsMap();
|
|
|
|
WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
|
2012-06-20 08:34:58 +08:00
|
|
|
WriteComments();
|
2011-10-29 06:54:21 +08:00
|
|
|
|
|
|
|
if (Chain) {
|
|
|
|
// Write the mapping information describing our module dependencies and how
|
|
|
|
// each of those modules were mapped into our own offset/ID space, so that
|
|
|
|
// the reader can build the appropriate mapping to its own offset/ID space.
|
|
|
|
// The map consists solely of a blob with the following format:
|
|
|
|
// *(module-name-len:i16 module-name:len*i8
|
|
|
|
// source-location-offset:i32
|
|
|
|
// identifier-id:i32
|
|
|
|
// preprocessed-entity-id:i32
|
|
|
|
// macro-definition-id:i32
|
2011-12-01 08:59:36 +08:00
|
|
|
// submodule-id:i32
|
2011-10-29 06:54:21 +08:00
|
|
|
// selector-id:i32
|
|
|
|
// declaration-id:i32
|
|
|
|
// c++-base-specifiers-id:i32
|
|
|
|
// type-id:i32)
|
|
|
|
//
|
|
|
|
llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev);
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<2048> Buffer;
|
2011-10-29 06:54:21 +08:00
|
|
|
{
|
|
|
|
llvm::raw_svector_ostream Out(Buffer);
|
|
|
|
for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(),
|
2011-12-03 02:58:38 +08:00
|
|
|
MEnd = Chain->ModuleMgr.end();
|
2011-10-29 06:54:21 +08:00
|
|
|
M != MEnd; ++M) {
|
|
|
|
StringRef FileName = (*M)->FileName;
|
|
|
|
io::Emit16(Out, FileName.size());
|
|
|
|
Out.write(FileName.data(), FileName.size());
|
|
|
|
io::Emit32(Out, (*M)->SLocEntryBaseOffset);
|
|
|
|
io::Emit32(Out, (*M)->BaseIdentifierID);
|
2012-10-10 07:05:51 +08:00
|
|
|
io::Emit32(Out, (*M)->BaseMacroID);
|
2011-10-29 06:54:21 +08:00
|
|
|
io::Emit32(Out, (*M)->BasePreprocessedEntityID);
|
2011-12-01 08:59:36 +08:00
|
|
|
io::Emit32(Out, (*M)->BaseSubmoduleID);
|
2011-10-29 06:54:21 +08:00
|
|
|
io::Emit32(Out, (*M)->BaseSelectorID);
|
|
|
|
io::Emit32(Out, (*M)->BaseDeclID);
|
|
|
|
io::Emit32(Out, (*M)->BaseTypeIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(MODULE_OFFSET_MAP);
|
|
|
|
Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
|
|
|
|
Buffer.data(), Buffer.size());
|
|
|
|
}
|
2011-11-30 12:39:39 +08:00
|
|
|
WritePreprocessor(PP, WritingModule != 0);
|
Implement two related optimizations that make de-serialization of
AST/PCH files more lazy:
- Don't preload all of the file source-location entries when reading
the AST file. Instead, load them lazily, when needed.
- Only look up header-search information (whether a header was already
#import'd, how many times it's been included, etc.) when it's needed
by the preprocessor, rather than pre-populating it.
Previously, we would pre-load all of the file source-location entries,
which also populated the header-search information structure. This was
a relatively minor performance issue, since we would end up stat()'ing
all of the headers stored within a AST/PCH file when the AST/PCH file
was loaded. In the normal PCH use case, the stat()s were cached, so
the cost--of preloading ~860 source-location entries in the Cocoa.h
case---was relatively low.
However, the recent optimization that replaced stat+open with
open+fstat turned this into a major problem, since the preloading of
source-location entries would now end up opening those files. Worse,
those files wouldn't be closed until the file manager was destroyed,
so just opening a Cocoa.h PCH file would hold on to ~860 file
descriptors, and it was easy to blow through the process's limit on
the number of open file descriptors.
By eliminating the preloading of these files, we neither open nor stat
the headers stored in the PCH/AST file until they're actually needed
for something. Concretely, we went from
*** HeaderSearch Stats:
835 files tracked.
364 #import/#pragma once files.
823 included exactly once.
6 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
835 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
with a trivial program that uses a chained PCH including a Cocoa PCH
to
*** HeaderSearch Stats:
4 files tracked.
1 #import/#pragma once files.
3 included exactly once.
2 max times a file is included.
3 #include/#include_next/#import.
0 #includes skipped due to the multi-include optimization.
1 framework lookups.
0 subframework lookups.
*** Source Manager Stats:
3 files mapped, 3 mem buffers mapped.
37460 SLocEntry's allocated, 11215575B of Sloc address space used.
62 bytes of files mapped, 0 files with line #'s computed.
for the same program.
llvm-svn: 125286
2011-02-11 01:09:37 +08:00
|
|
|
WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
|
2010-08-04 05:58:15 +08:00
|
|
|
WriteSelectors(SemaRef);
|
2010-07-24 03:11:11 +08:00
|
|
|
WriteReferencedSelectorsPool(SemaRef);
|
2011-11-30 12:39:39 +08:00
|
|
|
WriteIdentifierTable(PP, SemaRef.IdResolver, WritingModule != 0);
|
2011-02-16 03:46:30 +08:00
|
|
|
WriteFPPragmaOptions(SemaRef.getFPOptions());
|
|
|
|
WriteOpenCLExtensions(SemaRef);
|
2009-04-26 02:35:21 +08:00
|
|
|
|
2010-07-17 00:36:56 +08:00
|
|
|
WriteTypeDeclOffsets();
|
2011-01-15 04:54:07 +08:00
|
|
|
WritePragmaDiagnosticMappings(Context.getDiagnostics());
|
2009-04-18 13:55:16 +08:00
|
|
|
|
2011-03-07 02:41:18 +08:00
|
|
|
WriteCXXBaseSpecifiersOffsets();
|
2010-10-30 06:39:52 +08:00
|
|
|
|
2011-12-06 09:10:29 +08:00
|
|
|
// If we're emitting a module, write out the submodule information.
|
|
|
|
if (WritingModule)
|
|
|
|
WriteSubmodules(WritingModule);
|
|
|
|
|
2011-08-03 00:26:37 +08:00
|
|
|
Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
|
|
|
|
|
2010-07-28 07:01:28 +08:00
|
|
|
// Write the record containing external, unnamed definitions.
|
|
|
|
if (!ExternalDefinitions.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
|
|
|
// Write the record containing tentative definitions.
|
|
|
|
if (!TentativeDefinitions.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
2010-08-14 02:42:17 +08:00
|
|
|
// Write the record containing unused file scoped decls.
|
|
|
|
if (!UnusedFileScopedDecls.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
2010-08-06 02:21:25 +08:00
|
|
|
// Write the record containing weak undeclared identifiers.
|
|
|
|
if (!WeakUndeclaredIdentifiers.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS,
|
2010-08-06 02:21:25 +08:00
|
|
|
WeakUndeclaredIdentifiers);
|
|
|
|
|
2010-07-28 07:01:28 +08:00
|
|
|
// Write the record containing locally-scoped external definitions.
|
|
|
|
if (!LocallyScopedExternalDecls.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(LOCALLY_SCOPED_EXTERNAL_DECLS,
|
2010-07-28 07:01:28 +08:00
|
|
|
LocallyScopedExternalDecls);
|
|
|
|
|
|
|
|
// Write the record containing ext_vector type names.
|
|
|
|
if (!ExtVectorDecls.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
2010-08-06 02:21:25 +08:00
|
|
|
// Write the record containing VTable uses information.
|
|
|
|
if (!VTableUses.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(VTABLE_USES, VTableUses);
|
2010-08-06 02:21:25 +08:00
|
|
|
|
|
|
|
// Write the record containing dynamic classes declarations.
|
|
|
|
if (!DynamicClasses.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(DYNAMIC_CLASSES, DynamicClasses);
|
2010-08-06 02:21:25 +08:00
|
|
|
|
|
|
|
// Write the record containing pending implicit instantiations.
|
2010-08-25 16:44:16 +08:00
|
|
|
if (!PendingInstantiations.empty())
|
|
|
|
Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations);
|
2010-08-06 02:21:25 +08:00
|
|
|
|
|
|
|
// Write the record containing declaration references of Sema.
|
|
|
|
if (!SemaDeclRefs.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);
|
2011-08-12 09:39:19 +08:00
|
|
|
|
|
|
|
// Write the record containing CUDA-specific declaration references.
|
|
|
|
if (!CUDASpecialDeclRefs.empty())
|
|
|
|
Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs);
|
2011-05-05 07:29:54 +08:00
|
|
|
|
|
|
|
// Write the delegating constructors.
|
|
|
|
if (!DelegatingCtorDecls.empty())
|
|
|
|
Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
2011-08-12 09:39:19 +08:00
|
|
|
// Write the known namespaces.
|
|
|
|
if (!KnownNamespaces.empty())
|
|
|
|
Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
|
|
|
|
|
|
|
|
// Write the visible updates to DeclContexts.
|
2010-10-28 15:38:51 +08:00
|
|
|
for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator
|
2011-08-12 09:39:19 +08:00
|
|
|
I = UpdatedDeclContexts.begin(),
|
|
|
|
E = UpdatedDeclContexts.end();
|
|
|
|
I != E; ++I)
|
2010-08-24 08:50:09 +08:00
|
|
|
WriteDeclContextVisibleUpdate(*I);
|
|
|
|
|
2011-12-03 09:15:29 +08:00
|
|
|
if (!WritingModule) {
|
|
|
|
// Write the submodules that were imported, if any.
|
|
|
|
RecordData ImportedModules;
|
|
|
|
for (ASTContext::import_iterator I = Context.local_import_begin(),
|
|
|
|
IEnd = Context.local_import_end();
|
|
|
|
I != IEnd; ++I) {
|
|
|
|
assert(SubmoduleIDs.find(I->getImportedModule()) != SubmoduleIDs.end());
|
|
|
|
ImportedModules.push_back(SubmoduleIDs[I->getImportedModule()]);
|
|
|
|
}
|
|
|
|
if (!ImportedModules.empty()) {
|
|
|
|
// Sort module IDs.
|
|
|
|
llvm::array_pod_sort(ImportedModules.begin(), ImportedModules.end());
|
|
|
|
|
|
|
|
// Unique module IDs.
|
|
|
|
ImportedModules.erase(std::unique(ImportedModules.begin(),
|
|
|
|
ImportedModules.end()),
|
|
|
|
ImportedModules.end());
|
|
|
|
|
|
|
|
Stream.EmitRecord(IMPORTED_MODULES, ImportedModules);
|
|
|
|
}
|
2011-12-03 08:59:55 +08:00
|
|
|
}
|
2012-10-10 07:05:51 +08:00
|
|
|
|
|
|
|
WriteMacroUpdates();
|
2010-10-25 01:26:43 +08:00
|
|
|
WriteDeclUpdatesBlocks();
|
2011-08-12 09:39:19 +08:00
|
|
|
WriteDeclReplacementsBlock();
|
2011-12-23 05:40:42 +08:00
|
|
|
WriteMergedDecls();
|
2012-01-16 00:58:34 +08:00
|
|
|
WriteRedeclarations();
|
2012-01-27 09:47:08 +08:00
|
|
|
WriteObjCCategories();
|
Completely re-implement (de-)serialization of declaration
chains. The previous implementation relied heavily on the declaration
chain being stored as a (circular) linked list on disk, as it is in
memory. However, when deserializing from multiple modules, the
different chains could get mixed up, leading to broken declaration chains.
The new solution keeps track of the first and last declarations in the
chain for each module file. When we load a declaration, we search all
of the module files for redeclarations of that declaration, then
splice together all of the lists into a coherent whole (along with any
redeclarations that were actually parsed).
As a drive-by fix, (de-)serialize the redeclaration chains of
TypedefNameDecls, which had somehow gotten missed previously. Add a
test of this serialization.
This new scheme creates a redeclaration table that is fairly large in
the PCH file (on the order of 400k for Cocoa.h's 12MB PCH file). The
table is mmap'd in and searched via a binary search, but it's still
quite large. A future tweak will eliminate entries for declarations
that have no redeclarations anywhere, and should
drastically reduce the size of this table.
llvm-svn: 146841
2011-12-18 07:38:30 +08:00
|
|
|
|
2011-08-12 09:39:19 +08:00
|
|
|
// Some simple statistics
|
2010-07-28 07:01:28 +08:00
|
|
|
Record.clear();
|
|
|
|
Record.push_back(NumStatements);
|
|
|
|
Record.push_back(NumMacros);
|
|
|
|
Record.push_back(NumLexicalDeclContexts);
|
|
|
|
Record.push_back(NumVisibleDeclContexts);
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(STATISTICS, Record);
|
2010-07-13 06:02:52 +08:00
|
|
|
Stream.ExitBlock();
|
|
|
|
}
|
|
|
|
|
2012-10-10 07:05:51 +08:00
|
|
|
void ASTWriter::WriteMacroUpdates() {
|
|
|
|
if (MacroUpdates.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
for (MacroUpdatesMap::iterator I = MacroUpdates.begin(),
|
|
|
|
E = MacroUpdates.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
addMacroRef(I->first, Record);
|
|
|
|
AddSourceLocation(I->second.UndefLoc, Record);
|
2012-10-12 08:16:50 +08:00
|
|
|
Record.push_back(inferSubmoduleIDFromLocation(I->second.UndefLoc));
|
2012-10-10 07:05:51 +08:00
|
|
|
}
|
|
|
|
Stream.EmitRecord(MACRO_UPDATES, Record);
|
|
|
|
}
|
|
|
|
|
2011-09-17 08:05:03 +08:00
|
|
|
/// \brief Go through the declaration update blocks and resolve declaration
|
|
|
|
/// pointers into declaration IDs.
|
|
|
|
void ASTWriter::ResolveDeclUpdatesBlocks() {
|
|
|
|
for (DeclUpdateMap::iterator
|
|
|
|
I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) {
|
|
|
|
const Decl *D = I->first;
|
|
|
|
UpdateRecord &URec = I->second;
|
|
|
|
|
2011-11-13 05:07:46 +08:00
|
|
|
if (isRewritten(D))
|
2011-09-17 08:05:03 +08:00
|
|
|
continue; // The decl will be written completely
|
|
|
|
|
|
|
|
unsigned Idx = 0, N = URec.size();
|
|
|
|
while (Idx < N) {
|
|
|
|
switch ((DeclUpdateKind)URec[Idx++]) {
|
|
|
|
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
|
|
|
|
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
|
|
|
|
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
|
|
|
|
URec[Idx] = GetDeclRef(reinterpret_cast<Decl *>(URec[Idx]));
|
|
|
|
++Idx;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
|
|
|
|
++Idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:43 +08:00
|
|
|
void ASTWriter::WriteDeclUpdatesBlocks() {
|
2010-10-25 01:26:36 +08:00
|
|
|
if (DeclUpdates.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
RecordData OffsetsRecord;
|
2011-06-03 10:27:19 +08:00
|
|
|
Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
|
2010-10-25 01:26:36 +08:00
|
|
|
for (DeclUpdateMap::iterator
|
|
|
|
I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) {
|
|
|
|
const Decl *D = I->first;
|
|
|
|
UpdateRecord &URec = I->second;
|
|
|
|
|
2011-11-13 05:07:46 +08:00
|
|
|
if (isRewritten(D))
|
2010-10-25 01:26:46 +08:00
|
|
|
continue; // The decl will be written completely,no need to store updates.
|
|
|
|
|
2010-10-25 01:26:36 +08:00
|
|
|
uint64_t Offset = Stream.GetCurrentBitNo();
|
|
|
|
Stream.EmitRecord(DECL_UPDATES, URec);
|
|
|
|
|
|
|
|
OffsetsRecord.push_back(GetDeclRef(D));
|
|
|
|
OffsetsRecord.push_back(Offset);
|
|
|
|
}
|
|
|
|
Stream.ExitBlock();
|
|
|
|
Stream.EmitRecord(DECL_UPDATE_OFFSETS, OffsetsRecord);
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:43 +08:00
|
|
|
void ASTWriter::WriteDeclReplacementsBlock() {
|
2010-08-13 08:28:03 +08:00
|
|
|
if (ReplacedDecls.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
RecordData Record;
|
2011-10-31 15:20:15 +08:00
|
|
|
for (SmallVector<ReplacedDeclInfo, 16>::iterator
|
2010-08-13 08:28:03 +08:00
|
|
|
I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) {
|
2011-10-31 15:20:15 +08:00
|
|
|
Record.push_back(I->ID);
|
|
|
|
Record.push_back(I->Offset);
|
|
|
|
Record.push_back(I->Loc);
|
2010-08-13 08:28:03 +08:00
|
|
|
}
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(DECL_REPLACEMENTS, Record);
|
2010-08-13 08:28:03 +08:00
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Record.push_back(Loc.getRawEncoding());
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddSourceRange(SourceRange Range, RecordDataImpl &Record) {
|
2010-05-08 05:43:38 +08:00
|
|
|
AddSourceLocation(Range.getBegin(), Record);
|
|
|
|
AddSourceLocation(Range.getEnd(), Record);
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddAPInt(const llvm::APInt &Value, RecordDataImpl &Record) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Record.push_back(Value.getBitWidth());
|
2010-09-07 07:43:28 +08:00
|
|
|
const uint64_t *Words = Value.getRawData();
|
|
|
|
Record.append(Words, Words + Value.getNumWords());
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddAPSInt(const llvm::APSInt &Value, RecordDataImpl &Record) {
|
2009-04-14 02:14:40 +08:00
|
|
|
Record.push_back(Value.isUnsigned());
|
|
|
|
AddAPInt(Value, Record);
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddAPFloat(const llvm::APFloat &Value, RecordDataImpl &Record) {
|
2009-04-15 05:55:33 +08:00
|
|
|
AddAPInt(Value.bitcastToAPInt(), Record);
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record) {
|
2009-04-23 02:49:13 +08:00
|
|
|
Record.push_back(getIdentifierRef(II));
|
|
|
|
}
|
|
|
|
|
2012-10-10 07:05:51 +08:00
|
|
|
void ASTWriter::addMacroRef(MacroInfo *MI, RecordDataImpl &Record) {
|
|
|
|
Record.push_back(getMacroRef(MI));
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
|
2009-04-23 02:49:13 +08:00
|
|
|
if (II == 0)
|
|
|
|
return 0;
|
2009-04-11 08:14:32 +08:00
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
IdentID &ID = IdentifierIDs[II];
|
2009-04-11 08:14:32 +08:00
|
|
|
if (ID == 0)
|
2010-07-24 07:49:55 +08:00
|
|
|
ID = NextIdentID++;
|
2009-04-23 02:49:13 +08:00
|
|
|
return ID;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2012-10-10 07:05:51 +08:00
|
|
|
MacroID ASTWriter::getMacroRef(MacroInfo *MI) {
|
|
|
|
// Don't emit builtin macros like __LINE__ to the AST file unless they
|
|
|
|
// have been redefined by the header (in which case they are not
|
|
|
|
// isBuiltinMacro).
|
|
|
|
if (MI == 0 || MI->isBuiltinMacro())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
MacroID &ID = MacroIDs[MI];
|
|
|
|
if (ID == 0)
|
|
|
|
ID = NextMacroID++;
|
|
|
|
return ID;
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) {
|
2010-08-05 01:20:04 +08:00
|
|
|
Record.push_back(getSelectorRef(SelRef));
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
SelectorID ASTWriter::getSelectorRef(Selector Sel) {
|
2010-08-05 01:20:04 +08:00
|
|
|
if (Sel.getAsOpaquePtr() == 0) {
|
|
|
|
return 0;
|
2009-04-23 18:39:46 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
SelectorID &SID = SelectorIDs[Sel];
|
2010-08-05 02:21:41 +08:00
|
|
|
if (SID == 0 && Chain) {
|
|
|
|
// This might trigger a ReadSelector callback, which will set the ID for
|
|
|
|
// this selector.
|
|
|
|
Chain->LoadSelector(Sel);
|
|
|
|
}
|
2009-04-23 18:39:46 +08:00
|
|
|
if (SID == 0) {
|
2010-08-05 02:21:41 +08:00
|
|
|
SID = NextSelectorID++;
|
2009-04-23 18:39:46 +08:00
|
|
|
}
|
2010-08-05 01:20:04 +08:00
|
|
|
return SID;
|
2009-04-23 18:39:46 +08:00
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordDataImpl &Record) {
|
2010-05-10 08:25:06 +08:00
|
|
|
AddDeclRef(Temp->getDestructor(), Record);
|
|
|
|
}
|
|
|
|
|
2010-10-30 06:39:52 +08:00
|
|
|
void ASTWriter::AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases,
|
|
|
|
CXXBaseSpecifier const *BasesEnd,
|
|
|
|
RecordDataImpl &Record) {
|
|
|
|
assert(Bases != BasesEnd && "Empty base-specifier sets are not recorded");
|
|
|
|
CXXBaseSpecifiersToWrite.push_back(
|
|
|
|
QueuedCXXBaseSpecifiers(NextCXXBaseSpecifiersID,
|
|
|
|
Bases, BasesEnd));
|
|
|
|
Record.push_back(NextCXXBaseSpecifiersID++);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
|
2010-06-22 17:54:59 +08:00
|
|
|
const TemplateArgumentLocInfo &Arg,
|
2010-10-25 01:26:40 +08:00
|
|
|
RecordDataImpl &Record) {
|
2010-06-22 17:54:59 +08:00
|
|
|
switch (Kind) {
|
2009-10-29 16:12:44 +08:00
|
|
|
case TemplateArgument::Expression:
|
2010-06-22 17:54:59 +08:00
|
|
|
AddStmt(Arg.getAsExpr());
|
2009-10-29 16:12:44 +08:00
|
|
|
break;
|
|
|
|
case TemplateArgument::Type:
|
2010-06-22 17:54:59 +08:00
|
|
|
AddTypeSourceInfo(Arg.getAsTypeSourceInfo(), Record);
|
2009-10-29 16:12:44 +08:00
|
|
|
break;
|
2009-11-11 09:00:40 +08:00
|
|
|
case TemplateArgument::Template:
|
2011-03-03 01:09:35 +08:00
|
|
|
AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record);
|
2011-01-06 02:58:31 +08:00
|
|
|
AddSourceLocation(Arg.getTemplateNameLoc(), Record);
|
|
|
|
break;
|
|
|
|
case TemplateArgument::TemplateExpansion:
|
2011-03-03 01:09:35 +08:00
|
|
|
AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record);
|
2010-06-28 17:31:42 +08:00
|
|
|
AddSourceLocation(Arg.getTemplateNameLoc(), Record);
|
2011-01-06 01:40:24 +08:00
|
|
|
AddSourceLocation(Arg.getTemplateEllipsisLoc(), Record);
|
2009-11-11 09:00:40 +08:00
|
|
|
break;
|
2009-10-29 16:12:44 +08:00
|
|
|
case TemplateArgument::Null:
|
|
|
|
case TemplateArgument::Integral:
|
|
|
|
case TemplateArgument::Declaration:
|
2012-09-26 10:36:12 +08:00
|
|
|
case TemplateArgument::NullPtr:
|
2009-10-29 16:12:44 +08:00
|
|
|
case TemplateArgument::Pack:
|
2012-09-26 10:36:12 +08:00
|
|
|
// FIXME: Is this right?
|
2009-10-29 16:12:44 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
|
2010-10-25 01:26:40 +08:00
|
|
|
RecordDataImpl &Record) {
|
2010-06-22 17:54:59 +08:00
|
|
|
AddTemplateArgument(Arg.getArgument(), Record);
|
2010-06-28 17:31:42 +08:00
|
|
|
|
|
|
|
if (Arg.getArgument().getKind() == TemplateArgument::Expression) {
|
|
|
|
bool InfoHasSameExpr
|
|
|
|
= Arg.getArgument().getAsExpr() == Arg.getLocInfo().getAsExpr();
|
|
|
|
Record.push_back(InfoHasSameExpr);
|
|
|
|
if (InfoHasSameExpr)
|
|
|
|
return; // Avoid storing the same expr twice.
|
|
|
|
}
|
2010-06-22 17:54:59 +08:00
|
|
|
AddTemplateArgumentLocInfo(Arg.getArgument().getKind(), Arg.getLocInfo(),
|
|
|
|
Record);
|
|
|
|
}
|
|
|
|
|
2011-02-25 08:36:19 +08:00
|
|
|
void ASTWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo,
|
|
|
|
RecordDataImpl &Record) {
|
2009-12-07 10:54:59 +08:00
|
|
|
if (TInfo == 0) {
|
2009-10-17 05:56:05 +08:00
|
|
|
AddTypeRef(QualType(), Record);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-02-25 08:36:19 +08:00
|
|
|
AddTypeLoc(TInfo->getTypeLoc(), Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTWriter::AddTypeLoc(TypeLoc TL, RecordDataImpl &Record) {
|
|
|
|
AddTypeRef(TL.getType(), Record);
|
|
|
|
|
2009-10-17 05:56:05 +08:00
|
|
|
TypeLocWriter TLW(*this, Record);
|
2011-02-25 08:36:19 +08:00
|
|
|
for (; !TL.isNull(); TL = TL.getNextTypeLoc())
|
2010-03-14 15:06:50 +08:00
|
|
|
TLW.Visit(TL);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddTypeRef(QualType T, RecordDataImpl &Record) {
|
2010-08-21 00:04:14 +08:00
|
|
|
Record.push_back(GetOrCreateTypeID(T));
|
|
|
|
}
|
|
|
|
|
2011-08-09 23:13:55 +08:00
|
|
|
TypeID ASTWriter::GetOrCreateTypeID( QualType T) {
|
|
|
|
return MakeTypeID(*Context, T,
|
2010-08-21 00:04:20 +08:00
|
|
|
std::bind1st(std::mem_fun(&ASTWriter::GetOrCreateTypeIdx), this));
|
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-08-21 00:04:27 +08:00
|
|
|
TypeID ASTWriter::getTypeID(QualType T) const {
|
2011-08-09 23:13:55 +08:00
|
|
|
return MakeTypeID(*Context, T,
|
2010-08-21 00:04:20 +08:00
|
|
|
std::bind1st(std::mem_fun(&ASTWriter::getTypeIdx), this));
|
2010-08-21 00:04:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TypeIdx ASTWriter::GetOrCreateTypeIdx(QualType T) {
|
|
|
|
if (T.isNull())
|
|
|
|
return TypeIdx();
|
|
|
|
assert(!T.getLocalFastQualifiers());
|
|
|
|
|
2010-08-21 00:04:04 +08:00
|
|
|
TypeIdx &Idx = TypeIdxs[T];
|
2010-08-21 00:03:59 +08:00
|
|
|
if (Idx.getIndex() == 0) {
|
2012-07-03 03:19:01 +08:00
|
|
|
if (DoneWritingDeclsAndTypes) {
|
|
|
|
assert(0 && "New type seen after serializing all the types to emit!");
|
|
|
|
return TypeIdx();
|
|
|
|
}
|
|
|
|
|
2009-04-26 11:49:13 +08:00
|
|
|
// We haven't seen this type before. Assign it a new ID and put it
|
2009-09-25 03:53:00 +08:00
|
|
|
// into the queue of types to emit.
|
2010-08-21 00:03:59 +08:00
|
|
|
Idx = TypeIdx(NextTypeID++);
|
2009-10-17 08:13:19 +08:00
|
|
|
DeclTypesToEmit.push(T);
|
2009-04-26 11:49:13 +08:00
|
|
|
}
|
2010-08-21 00:04:09 +08:00
|
|
|
return Idx;
|
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-08-21 00:04:27 +08:00
|
|
|
TypeIdx ASTWriter::getTypeIdx(QualType T) const {
|
2010-08-21 00:04:09 +08:00
|
|
|
if (T.isNull())
|
|
|
|
return TypeIdx();
|
|
|
|
assert(!T.getLocalFastQualifiers());
|
|
|
|
|
2010-08-21 00:04:27 +08:00
|
|
|
TypeIdxMap::const_iterator I = TypeIdxs.find(T);
|
|
|
|
assert(I != TypeIdxs.end() && "Type not emitted!");
|
|
|
|
return I->second;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:36 +08:00
|
|
|
void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) {
|
2010-07-27 08:17:23 +08:00
|
|
|
Record.push_back(GetDeclRef(D));
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
DeclID ASTWriter::GetDeclRef(const Decl *D) {
|
2011-09-17 08:05:03 +08:00
|
|
|
assert(WritingAST && "Cannot request a declaration ID before AST writing");
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
if (D == 0) {
|
2010-07-27 08:17:23 +08:00
|
|
|
return 0;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
2012-01-06 06:33:30 +08:00
|
|
|
|
|
|
|
// If D comes from an AST file, its declaration ID is already known and
|
|
|
|
// fixed.
|
|
|
|
if (D->isFromASTFile())
|
|
|
|
return D->getGlobalID();
|
|
|
|
|
2010-10-06 02:37:06 +08:00
|
|
|
assert(!(reinterpret_cast<uintptr_t>(D) & 0x01) && "Invalid decl pointer");
|
2010-08-19 07:57:32 +08:00
|
|
|
DeclID &ID = DeclIDs[D];
|
2009-09-09 23:08:12 +08:00
|
|
|
if (ID == 0) {
|
2012-07-03 03:19:01 +08:00
|
|
|
if (DoneWritingDeclsAndTypes) {
|
|
|
|
assert(0 && "New decl seen after serializing all the decls to emit!");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// We haven't seen this declaration before. Give it a new ID and
|
|
|
|
// enqueue it in the list of declarations to emit.
|
2010-07-24 07:49:55 +08:00
|
|
|
ID = NextDeclID++;
|
2009-10-17 08:13:19 +08:00
|
|
|
DeclTypesToEmit.push(const_cast<Decl *>(D));
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-07-27 08:17:23 +08:00
|
|
|
return ID;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
DeclID ASTWriter::getDeclID(const Decl *D) {
|
2009-04-21 04:36:09 +08:00
|
|
|
if (D == 0)
|
|
|
|
return 0;
|
|
|
|
|
2012-01-06 06:33:30 +08:00
|
|
|
// If D comes from an AST file, its declaration ID is already known and
|
|
|
|
// fixed.
|
|
|
|
if (D->isFromASTFile())
|
|
|
|
return D->getGlobalID();
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!");
|
|
|
|
return DeclIDs[D];
|
|
|
|
}
|
|
|
|
|
2011-10-29 06:54:21 +08:00
|
|
|
static inline bool compLocDecl(std::pair<unsigned, serialization::DeclID> L,
|
|
|
|
std::pair<unsigned, serialization::DeclID> R) {
|
|
|
|
return L.first < R.first;
|
|
|
|
}
|
|
|
|
|
2011-10-29 07:57:43 +08:00
|
|
|
void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
|
2011-10-29 06:54:21 +08:00
|
|
|
assert(ID);
|
2011-10-29 07:57:43 +08:00
|
|
|
assert(D);
|
|
|
|
|
|
|
|
SourceLocation Loc = D->getLocation();
|
|
|
|
if (Loc.isInvalid())
|
|
|
|
return;
|
2011-10-29 06:54:21 +08:00
|
|
|
|
|
|
|
// We only keep track of the file-level declarations of each file.
|
|
|
|
if (!D->getLexicalDeclContext()->isFileContext())
|
|
|
|
return;
|
2012-02-25 03:45:46 +08:00
|
|
|
// FIXME: ParmVarDecls that are part of a function type of a parameter of
|
|
|
|
// a function/objc method, should not have TU as lexical context.
|
2012-02-24 09:12:38 +08:00
|
|
|
if (isa<ParmVarDecl>(D))
|
|
|
|
return;
|
2011-10-29 06:54:21 +08:00
|
|
|
|
|
|
|
SourceManager &SM = Context->getSourceManager();
|
2011-10-29 07:57:43 +08:00
|
|
|
SourceLocation FileLoc = SM.getFileLoc(Loc);
|
2011-10-29 06:54:21 +08:00
|
|
|
assert(SM.isLocalSourceLocation(FileLoc));
|
2011-10-29 07:57:47 +08:00
|
|
|
FileID FID;
|
|
|
|
unsigned Offset;
|
|
|
|
llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
|
2011-10-29 06:54:21 +08:00
|
|
|
if (FID.isInvalid())
|
|
|
|
return;
|
2012-10-03 05:09:17 +08:00
|
|
|
assert(SM.getSLocEntry(FID).isFile());
|
2011-10-29 06:54:21 +08:00
|
|
|
|
2012-10-03 05:09:17 +08:00
|
|
|
DeclIDInFileInfo *&Info = FileDeclIDs[FID];
|
2011-10-29 06:54:21 +08:00
|
|
|
if (!Info)
|
|
|
|
Info = new DeclIDInFileInfo();
|
|
|
|
|
2011-10-29 07:57:47 +08:00
|
|
|
std::pair<unsigned, serialization::DeclID> LocDecl(Offset, ID);
|
2011-10-29 06:54:21 +08:00
|
|
|
LocDeclIDsTy &Decls = Info->DeclIDs;
|
|
|
|
|
2011-10-29 07:57:47 +08:00
|
|
|
if (Decls.empty() || Decls.back().first <= Offset) {
|
2011-10-29 06:54:21 +08:00
|
|
|
Decls.push_back(LocDecl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LocDeclIDsTy::iterator
|
|
|
|
I = std::upper_bound(Decls.begin(), Decls.end(), LocDecl, compLocDecl);
|
|
|
|
|
|
|
|
Decls.insert(I, LocDecl);
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddDeclarationName(DeclarationName Name, RecordDataImpl &Record) {
|
2009-04-27 15:35:58 +08:00
|
|
|
// FIXME: Emit a stable enum for NameKind. 0 = Identifier etc.
|
2009-04-10 06:27:44 +08:00
|
|
|
Record.push_back(Name.getNameKind());
|
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
AddIdentifierRef(Name.getAsIdentifierInfo(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
2009-04-23 18:39:46 +08:00
|
|
|
AddSelectorRef(Name.getObjCSelector(), Record);
|
2009-04-10 06:27:44 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
AddTypeRef(Name.getCXXNameType(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
Record.push_back(Name.getCXXOverloadedOperator());
|
|
|
|
break;
|
|
|
|
|
2009-11-29 15:34:05 +08:00
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
AddIdentifierRef(Name.getCXXLiteralIdentifier(), Record);
|
|
|
|
break;
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
// No extra data to emit
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-05-08 05:43:38 +08:00
|
|
|
|
2010-10-16 02:21:24 +08:00
|
|
|
void ASTWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc,
|
2010-10-25 01:26:40 +08:00
|
|
|
DeclarationName Name, RecordDataImpl &Record) {
|
2010-10-16 02:21:24 +08:00
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
AddTypeSourceInfo(DNLoc.NamedType.TInfo, Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
AddSourceLocation(
|
|
|
|
SourceLocation::getFromRawEncoding(DNLoc.CXXOperatorName.BeginOpNameLoc),
|
|
|
|
Record);
|
|
|
|
AddSourceLocation(
|
|
|
|
SourceLocation::getFromRawEncoding(DNLoc.CXXOperatorName.EndOpNameLoc),
|
|
|
|
Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
AddSourceLocation(
|
|
|
|
SourceLocation::getFromRawEncoding(DNLoc.CXXLiteralOperatorName.OpNameLoc),
|
|
|
|
Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTWriter::AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
|
2010-10-25 01:26:40 +08:00
|
|
|
RecordDataImpl &Record) {
|
2010-10-16 02:21:24 +08:00
|
|
|
AddDeclarationName(NameInfo.getName(), Record);
|
|
|
|
AddSourceLocation(NameInfo.getLoc(), Record);
|
|
|
|
AddDeclarationNameLoc(NameInfo.getInfo(), NameInfo.getName(), Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTWriter::AddQualifierInfo(const QualifierInfo &Info,
|
2010-10-25 01:26:40 +08:00
|
|
|
RecordDataImpl &Record) {
|
2011-02-25 10:25:35 +08:00
|
|
|
AddNestedNameSpecifierLoc(Info.QualifierLoc, Record);
|
2010-10-16 02:21:24 +08:00
|
|
|
Record.push_back(Info.NumTemplParamLists);
|
|
|
|
for (unsigned i=0, e=Info.NumTemplParamLists; i != e; ++i)
|
|
|
|
AddTemplateParameterList(Info.TemplParamLists[i], Record);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
|
2010-10-25 01:26:40 +08:00
|
|
|
RecordDataImpl &Record) {
|
2010-05-08 05:43:38 +08:00
|
|
|
// Nested name specifiers usually aren't too long. I think that 8 would
|
2011-04-15 13:22:18 +08:00
|
|
|
// typically accommodate the vast majority.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<NestedNameSpecifier *, 8> NestedNames;
|
2010-05-08 05:43:38 +08:00
|
|
|
|
|
|
|
// Push each of the NNS's onto a stack for serialization in reverse order.
|
|
|
|
while (NNS) {
|
|
|
|
NestedNames.push_back(NNS);
|
|
|
|
NNS = NNS->getPrefix();
|
|
|
|
}
|
|
|
|
|
|
|
|
Record.push_back(NestedNames.size());
|
|
|
|
while(!NestedNames.empty()) {
|
|
|
|
NNS = NestedNames.pop_back_val();
|
|
|
|
NestedNameSpecifier::SpecifierKind Kind = NNS->getKind();
|
|
|
|
Record.push_back(Kind);
|
|
|
|
switch (Kind) {
|
|
|
|
case NestedNameSpecifier::Identifier:
|
|
|
|
AddIdentifierRef(NNS->getAsIdentifier(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Namespace:
|
|
|
|
AddDeclRef(NNS->getAsNamespace(), Record);
|
|
|
|
break;
|
|
|
|
|
2011-02-24 10:36:08 +08:00
|
|
|
case NestedNameSpecifier::NamespaceAlias:
|
|
|
|
AddDeclRef(NNS->getAsNamespaceAlias(), Record);
|
|
|
|
break;
|
|
|
|
|
2010-05-08 05:43:38 +08:00
|
|
|
case NestedNameSpecifier::TypeSpec:
|
|
|
|
case NestedNameSpecifier::TypeSpecWithTemplate:
|
|
|
|
AddTypeRef(QualType(NNS->getAsType(), 0), Record);
|
|
|
|
Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Global:
|
|
|
|
// Don't need to write an associated value.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-06-20 03:28:53 +08:00
|
|
|
|
2011-02-25 08:36:19 +08:00
|
|
|
void ASTWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
|
|
|
|
RecordDataImpl &Record) {
|
|
|
|
// Nested name specifiers usually aren't too long. I think that 8 would
|
2011-04-15 13:22:18 +08:00
|
|
|
// typically accommodate the vast majority.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<NestedNameSpecifierLoc , 8> NestedNames;
|
2011-02-25 08:36:19 +08:00
|
|
|
|
|
|
|
// Push each of the nested-name-specifiers's onto a stack for
|
|
|
|
// serialization in reverse order.
|
|
|
|
while (NNS) {
|
|
|
|
NestedNames.push_back(NNS);
|
|
|
|
NNS = NNS.getPrefix();
|
|
|
|
}
|
|
|
|
|
|
|
|
Record.push_back(NestedNames.size());
|
|
|
|
while(!NestedNames.empty()) {
|
|
|
|
NNS = NestedNames.pop_back_val();
|
|
|
|
NestedNameSpecifier::SpecifierKind Kind
|
|
|
|
= NNS.getNestedNameSpecifier()->getKind();
|
|
|
|
Record.push_back(Kind);
|
|
|
|
switch (Kind) {
|
|
|
|
case NestedNameSpecifier::Identifier:
|
|
|
|
AddIdentifierRef(NNS.getNestedNameSpecifier()->getAsIdentifier(), Record);
|
|
|
|
AddSourceRange(NNS.getLocalSourceRange(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Namespace:
|
|
|
|
AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespace(), Record);
|
|
|
|
AddSourceRange(NNS.getLocalSourceRange(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::NamespaceAlias:
|
|
|
|
AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(), Record);
|
|
|
|
AddSourceRange(NNS.getLocalSourceRange(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::TypeSpec:
|
|
|
|
case NestedNameSpecifier::TypeSpecWithTemplate:
|
|
|
|
Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate);
|
|
|
|
AddTypeLoc(NNS.getTypeLoc(), Record);
|
|
|
|
AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Global:
|
|
|
|
AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddTemplateName(TemplateName Name, RecordDataImpl &Record) {
|
2010-10-21 11:16:25 +08:00
|
|
|
TemplateName::NameKind Kind = Name.getKind();
|
2010-06-20 03:28:53 +08:00
|
|
|
Record.push_back(Kind);
|
|
|
|
switch (Kind) {
|
|
|
|
case TemplateName::Template:
|
|
|
|
AddDeclRef(Name.getAsTemplateDecl(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TemplateName::OverloadedTemplate: {
|
|
|
|
OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate();
|
|
|
|
Record.push_back(OvT->size());
|
|
|
|
for (OverloadedTemplateStorage::iterator I = OvT->begin(), E = OvT->end();
|
|
|
|
I != E; ++I)
|
|
|
|
AddDeclRef(*I, Record);
|
|
|
|
break;
|
|
|
|
}
|
2010-10-21 11:16:25 +08:00
|
|
|
|
2010-06-20 03:28:53 +08:00
|
|
|
case TemplateName::QualifiedTemplate: {
|
|
|
|
QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName();
|
|
|
|
AddNestedNameSpecifier(QualT->getQualifier(), Record);
|
|
|
|
Record.push_back(QualT->hasTemplateKeyword());
|
|
|
|
AddDeclRef(QualT->getTemplateDecl(), Record);
|
|
|
|
break;
|
|
|
|
}
|
2010-10-21 11:16:25 +08:00
|
|
|
|
2010-06-20 03:28:53 +08:00
|
|
|
case TemplateName::DependentTemplate: {
|
|
|
|
DependentTemplateName *DepT = Name.getAsDependentTemplateName();
|
|
|
|
AddNestedNameSpecifier(DepT->getQualifier(), Record);
|
|
|
|
Record.push_back(DepT->isIdentifier());
|
|
|
|
if (DepT->isIdentifier())
|
|
|
|
AddIdentifierRef(DepT->getIdentifier(), Record);
|
|
|
|
else
|
|
|
|
Record.push_back(DepT->getOperator());
|
|
|
|
break;
|
|
|
|
}
|
2011-06-30 16:33:18 +08:00
|
|
|
|
|
|
|
case TemplateName::SubstTemplateTemplateParm: {
|
|
|
|
SubstTemplateTemplateParmStorage *subst
|
|
|
|
= Name.getAsSubstTemplateTemplateParm();
|
|
|
|
AddDeclRef(subst->getParameter(), Record);
|
|
|
|
AddTemplateName(subst->getReplacement(), Record);
|
|
|
|
break;
|
|
|
|
}
|
2011-01-15 14:45:20 +08:00
|
|
|
|
|
|
|
case TemplateName::SubstTemplateTemplateParmPack: {
|
|
|
|
SubstTemplateTemplateParmPackStorage *SubstPack
|
|
|
|
= Name.getAsSubstTemplateTemplateParmPack();
|
|
|
|
AddDeclRef(SubstPack->getParameterPack(), Record);
|
|
|
|
AddTemplateArgument(SubstPack->getArgumentPack(), Record);
|
|
|
|
break;
|
|
|
|
}
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-21 11:16:25 +08:00
|
|
|
void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
|
2010-10-25 01:26:40 +08:00
|
|
|
RecordDataImpl &Record) {
|
2010-06-20 03:28:53 +08:00
|
|
|
Record.push_back(Arg.getKind());
|
|
|
|
switch (Arg.getKind()) {
|
|
|
|
case TemplateArgument::Null:
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Type:
|
|
|
|
AddTypeRef(Arg.getAsType(), Record);
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Declaration:
|
|
|
|
AddDeclRef(Arg.getAsDecl(), Record);
|
2012-09-26 10:36:12 +08:00
|
|
|
Record.push_back(Arg.isDeclForReferenceParam());
|
|
|
|
break;
|
|
|
|
case TemplateArgument::NullPtr:
|
|
|
|
AddTypeRef(Arg.getNullPtrType(), Record);
|
2010-06-20 03:28:53 +08:00
|
|
|
break;
|
|
|
|
case TemplateArgument::Integral:
|
2012-06-07 23:09:51 +08:00
|
|
|
AddAPSInt(Arg.getAsIntegral(), Record);
|
2010-06-20 03:28:53 +08:00
|
|
|
AddTypeRef(Arg.getIntegralType(), Record);
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Template:
|
2011-01-15 07:41:42 +08:00
|
|
|
AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
|
|
|
|
break;
|
2011-01-06 02:58:31 +08:00
|
|
|
case TemplateArgument::TemplateExpansion:
|
|
|
|
AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
|
2011-01-15 07:41:42 +08:00
|
|
|
if (llvm::Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
|
|
|
|
Record.push_back(*NumExpansions + 1);
|
|
|
|
else
|
|
|
|
Record.push_back(0);
|
2010-06-20 03:28:53 +08:00
|
|
|
break;
|
|
|
|
case TemplateArgument::Expression:
|
|
|
|
AddStmt(Arg.getAsExpr());
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Pack:
|
|
|
|
Record.push_back(Arg.pack_size());
|
|
|
|
for (TemplateArgument::pack_iterator I=Arg.pack_begin(), E=Arg.pack_end();
|
|
|
|
I != E; ++I)
|
|
|
|
AddTemplateArgument(*I, Record);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-06-23 21:48:30 +08:00
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::AddTemplateParameterList(const TemplateParameterList *TemplateParams,
|
2010-10-25 01:26:40 +08:00
|
|
|
RecordDataImpl &Record) {
|
2010-06-23 21:48:30 +08:00
|
|
|
assert(TemplateParams && "No TemplateParams!");
|
|
|
|
AddSourceLocation(TemplateParams->getTemplateLoc(), Record);
|
|
|
|
AddSourceLocation(TemplateParams->getLAngleLoc(), Record);
|
|
|
|
AddSourceLocation(TemplateParams->getRAngleLoc(), Record);
|
|
|
|
Record.push_back(TemplateParams->size());
|
|
|
|
for (TemplateParameterList::const_iterator
|
|
|
|
P = TemplateParams->begin(), PEnd = TemplateParams->end();
|
|
|
|
P != PEnd; ++P)
|
|
|
|
AddDeclRef(*P, Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Emit a template argument list.
|
|
|
|
void
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs,
|
2010-10-25 01:26:40 +08:00
|
|
|
RecordDataImpl &Record) {
|
2010-06-23 21:48:30 +08:00
|
|
|
assert(TemplateArgs && "No TemplateArgs!");
|
2010-11-08 07:05:16 +08:00
|
|
|
Record.push_back(TemplateArgs->size());
|
|
|
|
for (int i=0, e = TemplateArgs->size(); i != e; ++i)
|
2010-06-23 21:48:30 +08:00
|
|
|
AddTemplateArgument(TemplateArgs->get(i), Record);
|
|
|
|
}
|
2010-07-02 19:55:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-10-25 01:26:40 +08:00
|
|
|
ASTWriter::AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record) {
|
2010-07-02 19:55:32 +08:00
|
|
|
Record.push_back(Set.size());
|
|
|
|
for (UnresolvedSetImpl::const_iterator
|
|
|
|
I = Set.begin(), E = Set.end(); I != E; ++I) {
|
|
|
|
AddDeclRef(I.getDecl(), Record);
|
|
|
|
Record.push_back(I.getAccess());
|
|
|
|
}
|
|
|
|
}
|
2010-07-03 07:30:27 +08:00
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
|
2010-10-25 01:26:40 +08:00
|
|
|
RecordDataImpl &Record) {
|
2010-07-03 07:30:27 +08:00
|
|
|
Record.push_back(Base.isVirtual());
|
|
|
|
Record.push_back(Base.isBaseOfClass());
|
|
|
|
Record.push_back(Base.getAccessSpecifierAsWritten());
|
2011-02-06 03:23:19 +08:00
|
|
|
Record.push_back(Base.getInheritConstructors());
|
2010-07-27 00:56:01 +08:00
|
|
|
AddTypeSourceInfo(Base.getTypeSourceInfo(), Record);
|
2010-07-03 07:30:27 +08:00
|
|
|
AddSourceRange(Base.getSourceRange(), Record);
|
2011-01-04 06:36:02 +08:00
|
|
|
AddSourceLocation(Base.isPackExpansion()? Base.getEllipsisLoc()
|
|
|
|
: SourceLocation(),
|
|
|
|
Record);
|
2010-07-03 07:30:27 +08:00
|
|
|
}
|
2010-07-15 07:45:08 +08:00
|
|
|
|
2010-10-30 06:39:52 +08:00
|
|
|
void ASTWriter::FlushCXXBaseSpecifiers() {
|
|
|
|
RecordData Record;
|
|
|
|
for (unsigned I = 0, N = CXXBaseSpecifiersToWrite.size(); I != N; ++I) {
|
|
|
|
Record.clear();
|
|
|
|
|
|
|
|
// Record the offset of this base-specifier set.
|
2011-08-04 08:01:48 +08:00
|
|
|
unsigned Index = CXXBaseSpecifiersToWrite[I].ID - 1;
|
2010-10-30 06:39:52 +08:00
|
|
|
if (Index == CXXBaseSpecifiersOffsets.size())
|
|
|
|
CXXBaseSpecifiersOffsets.push_back(Stream.GetCurrentBitNo());
|
|
|
|
else {
|
|
|
|
if (Index > CXXBaseSpecifiersOffsets.size())
|
|
|
|
CXXBaseSpecifiersOffsets.resize(Index + 1);
|
|
|
|
CXXBaseSpecifiersOffsets[Index] = Stream.GetCurrentBitNo();
|
|
|
|
}
|
|
|
|
|
|
|
|
const CXXBaseSpecifier *B = CXXBaseSpecifiersToWrite[I].Bases,
|
|
|
|
*BEnd = CXXBaseSpecifiersToWrite[I].BasesEnd;
|
|
|
|
Record.push_back(BEnd - B);
|
|
|
|
for (; B != BEnd; ++B)
|
|
|
|
AddCXXBaseSpecifier(*B, Record);
|
|
|
|
Stream.EmitRecord(serialization::DECL_CXX_BASE_SPECIFIERS, Record);
|
2010-10-30 12:28:16 +08:00
|
|
|
|
|
|
|
// Flush any expressions that were written as part of the base specifiers.
|
|
|
|
FlushStmts();
|
2010-10-30 06:39:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CXXBaseSpecifiersToWrite.clear();
|
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
void ASTWriter::AddCXXCtorInitializers(
|
|
|
|
const CXXCtorInitializer * const *CtorInitializers,
|
|
|
|
unsigned NumCtorInitializers,
|
|
|
|
RecordDataImpl &Record) {
|
|
|
|
Record.push_back(NumCtorInitializers);
|
|
|
|
for (unsigned i=0; i != NumCtorInitializers; ++i) {
|
|
|
|
const CXXCtorInitializer *Init = CtorInitializers[i];
|
2010-08-09 18:54:12 +08:00
|
|
|
|
|
|
|
if (Init->isBaseInitializer()) {
|
2011-05-04 09:19:08 +08:00
|
|
|
Record.push_back(CTOR_INITIALIZER_BASE);
|
2011-11-01 09:16:03 +08:00
|
|
|
AddTypeSourceInfo(Init->getTypeSourceInfo(), Record);
|
2010-08-09 18:54:12 +08:00
|
|
|
Record.push_back(Init->isBaseVirtual());
|
2011-05-04 09:19:08 +08:00
|
|
|
} else if (Init->isDelegatingInitializer()) {
|
|
|
|
Record.push_back(CTOR_INITIALIZER_DELEGATING);
|
2011-11-01 09:16:03 +08:00
|
|
|
AddTypeSourceInfo(Init->getTypeSourceInfo(), Record);
|
2011-05-04 09:19:08 +08:00
|
|
|
} else if (Init->isMemberInitializer()){
|
|
|
|
Record.push_back(CTOR_INITIALIZER_MEMBER);
|
|
|
|
AddDeclRef(Init->getMember(), Record);
|
2010-08-09 18:54:12 +08:00
|
|
|
} else {
|
2011-05-04 09:19:08 +08:00
|
|
|
Record.push_back(CTOR_INITIALIZER_INDIRECT_MEMBER);
|
|
|
|
AddDeclRef(Init->getIndirectMember(), Record);
|
2010-08-09 18:54:12 +08:00
|
|
|
}
|
2010-12-04 17:14:42 +08:00
|
|
|
|
2010-08-09 18:54:12 +08:00
|
|
|
AddSourceLocation(Init->getMemberLocation(), Record);
|
|
|
|
AddStmt(Init->getInit());
|
|
|
|
AddSourceLocation(Init->getLParenLoc(), Record);
|
|
|
|
AddSourceLocation(Init->getRParenLoc(), Record);
|
|
|
|
Record.push_back(Init->isWritten());
|
|
|
|
if (Init->isWritten()) {
|
|
|
|
Record.push_back(Init->getSourceOrder());
|
|
|
|
} else {
|
|
|
|
Record.push_back(Init->getNumArrayIndices());
|
|
|
|
for (unsigned i=0, e=Init->getNumArrayIndices(); i != e; ++i)
|
|
|
|
AddDeclRef(Init->getArrayIndex(i), Record);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record) {
|
|
|
|
assert(D->DefinitionData);
|
|
|
|
struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData;
|
2012-02-15 01:54:36 +08:00
|
|
|
Record.push_back(Data.IsLambda);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.UserDeclaredConstructor);
|
|
|
|
Record.push_back(Data.UserDeclaredCopyConstructor);
|
2011-09-07 00:38:46 +08:00
|
|
|
Record.push_back(Data.UserDeclaredMoveConstructor);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.UserDeclaredCopyAssignment);
|
2011-09-07 00:38:46 +08:00
|
|
|
Record.push_back(Data.UserDeclaredMoveAssignment);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.UserDeclaredDestructor);
|
|
|
|
Record.push_back(Data.Aggregate);
|
|
|
|
Record.push_back(Data.PlainOldData);
|
|
|
|
Record.push_back(Data.Empty);
|
|
|
|
Record.push_back(Data.Polymorphic);
|
|
|
|
Record.push_back(Data.Abstract);
|
2011-04-30 18:07:30 +08:00
|
|
|
Record.push_back(Data.IsStandardLayout);
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
Record.push_back(Data.HasNoNonEmptyBases);
|
|
|
|
Record.push_back(Data.HasPrivateFields);
|
|
|
|
Record.push_back(Data.HasProtectedFields);
|
|
|
|
Record.push_back(Data.HasPublicFields);
|
2011-05-13 09:05:07 +08:00
|
|
|
Record.push_back(Data.HasMutableFields);
|
2012-02-25 15:33:38 +08:00
|
|
|
Record.push_back(Data.HasOnlyCMembers);
|
2012-05-07 09:07:30 +08:00
|
|
|
Record.push_back(Data.HasInClassInitializer);
|
2011-05-10 02:22:59 +08:00
|
|
|
Record.push_back(Data.HasTrivialDefaultConstructor);
|
2011-08-11 02:11:37 +08:00
|
|
|
Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
|
2012-02-25 15:33:38 +08:00
|
|
|
Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr);
|
|
|
|
Record.push_back(Data.HasConstexprDefaultConstructor);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.HasTrivialCopyConstructor);
|
2011-04-24 07:10:33 +08:00
|
|
|
Record.push_back(Data.HasTrivialMoveConstructor);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.HasTrivialCopyAssignment);
|
2011-04-24 07:10:33 +08:00
|
|
|
Record.push_back(Data.HasTrivialMoveAssignment);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.HasTrivialDestructor);
|
2012-02-25 15:33:38 +08:00
|
|
|
Record.push_back(Data.HasIrrelevantDestructor);
|
2011-04-24 10:49:34 +08:00
|
|
|
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.ComputedVisibleConversions);
|
2011-05-12 06:34:38 +08:00
|
|
|
Record.push_back(Data.UserProvidedDefaultConstructor);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.DeclaredDefaultConstructor);
|
|
|
|
Record.push_back(Data.DeclaredCopyConstructor);
|
2011-09-07 00:38:46 +08:00
|
|
|
Record.push_back(Data.DeclaredMoveConstructor);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.DeclaredCopyAssignment);
|
2011-09-07 00:38:46 +08:00
|
|
|
Record.push_back(Data.DeclaredMoveAssignment);
|
2010-10-25 01:26:40 +08:00
|
|
|
Record.push_back(Data.DeclaredDestructor);
|
2011-08-31 21:59:56 +08:00
|
|
|
Record.push_back(Data.FailedImplicitMoveConstructor);
|
|
|
|
Record.push_back(Data.FailedImplicitMoveAssignment);
|
2012-02-25 15:33:38 +08:00
|
|
|
// IsLambda bit is already saved.
|
2010-10-25 01:26:40 +08:00
|
|
|
|
|
|
|
Record.push_back(Data.NumBases);
|
2010-10-30 06:39:52 +08:00
|
|
|
if (Data.NumBases > 0)
|
|
|
|
AddCXXBaseSpecifiersRef(Data.getBases(), Data.getBases() + Data.NumBases,
|
|
|
|
Record);
|
|
|
|
|
2010-10-25 01:26:40 +08:00
|
|
|
// FIXME: Make VBases lazily computed when needed to avoid storing them.
|
|
|
|
Record.push_back(Data.NumVBases);
|
2010-10-30 06:39:52 +08:00
|
|
|
if (Data.NumVBases > 0)
|
|
|
|
AddCXXBaseSpecifiersRef(Data.getVBases(), Data.getVBases() + Data.NumVBases,
|
|
|
|
Record);
|
2010-10-25 01:26:40 +08:00
|
|
|
|
|
|
|
AddUnresolvedSet(Data.Conversions, Record);
|
|
|
|
AddUnresolvedSet(Data.VisibleConversions, Record);
|
|
|
|
// Data.Definition is the owning decl, no need to write it.
|
|
|
|
AddDeclRef(Data.FirstFriend, Record);
|
2012-02-15 01:54:36 +08:00
|
|
|
|
|
|
|
// Add lambda-specific data.
|
|
|
|
if (Data.IsLambda) {
|
|
|
|
CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData();
|
2012-02-22 03:11:17 +08:00
|
|
|
Record.push_back(Lambda.Dependent);
|
2012-02-15 01:54:36 +08:00
|
|
|
Record.push_back(Lambda.NumCaptures);
|
|
|
|
Record.push_back(Lambda.NumExplicitCaptures);
|
2012-02-21 03:44:39 +08:00
|
|
|
Record.push_back(Lambda.ManglingNumber);
|
2012-02-21 08:37:24 +08:00
|
|
|
AddDeclRef(Lambda.ContextDecl, Record);
|
2012-09-19 09:18:11 +08:00
|
|
|
AddTypeSourceInfo(Lambda.MethodTyInfo, Record);
|
2012-02-15 01:54:36 +08:00
|
|
|
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
|
|
|
|
LambdaExpr::Capture &Capture = Lambda.Captures[I];
|
|
|
|
AddSourceLocation(Capture.getLocation(), Record);
|
|
|
|
Record.push_back(Capture.isImplicit());
|
|
|
|
Record.push_back(Capture.getCaptureKind()); // FIXME: stable!
|
|
|
|
VarDecl *Var = Capture.capturesVariable()? Capture.getCapturedVar() : 0;
|
|
|
|
AddDeclRef(Var, Record);
|
|
|
|
AddSourceLocation(Capture.isPackExpansion()? Capture.getEllipsisLoc()
|
|
|
|
: SourceLocation(),
|
|
|
|
Record);
|
|
|
|
}
|
|
|
|
}
|
2010-10-25 01:26:40 +08:00
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:36 +08:00
|
|
|
void ASTWriter::ReaderInitialized(ASTReader *Reader) {
|
2010-07-30 08:29:29 +08:00
|
|
|
assert(Reader && "Cannot remove chain");
|
2011-08-18 12:12:04 +08:00
|
|
|
assert((!Chain || Chain == Reader) && "Cannot replace chain");
|
2010-07-30 08:29:29 +08:00
|
|
|
assert(FirstDeclID == NextDeclID &&
|
|
|
|
FirstTypeID == NextTypeID &&
|
|
|
|
FirstIdentID == NextIdentID &&
|
2012-10-10 07:05:51 +08:00
|
|
|
FirstMacroID == NextMacroID &&
|
2011-12-01 08:59:36 +08:00
|
|
|
FirstSubmoduleID == NextSubmoduleID &&
|
2010-08-05 02:21:41 +08:00
|
|
|
FirstSelectorID == NextSelectorID &&
|
2010-07-30 08:29:29 +08:00
|
|
|
"Setting chain after writing has started.");
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
|
2010-07-30 08:29:29 +08:00
|
|
|
Chain = Reader;
|
2010-10-25 01:26:36 +08:00
|
|
|
|
2011-08-18 12:12:04 +08:00
|
|
|
FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls();
|
|
|
|
FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
|
|
|
|
FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
|
2012-10-10 07:05:51 +08:00
|
|
|
FirstMacroID = NUM_PREDEF_MACRO_IDS + Chain->getTotalNumMacros();
|
2011-12-01 08:59:36 +08:00
|
|
|
FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules();
|
2011-08-18 12:12:04 +08:00
|
|
|
FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors();
|
2010-10-25 01:26:36 +08:00
|
|
|
NextDeclID = FirstDeclID;
|
|
|
|
NextTypeID = FirstTypeID;
|
|
|
|
NextIdentID = FirstIdentID;
|
2012-10-10 07:05:51 +08:00
|
|
|
NextMacroID = FirstMacroID;
|
2010-10-25 01:26:36 +08:00
|
|
|
NextSelectorID = FirstSelectorID;
|
2011-12-01 08:59:36 +08:00
|
|
|
NextSubmoduleID = FirstSubmoduleID;
|
2010-07-30 08:29:29 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
|
2010-07-24 07:49:55 +08:00
|
|
|
IdentifierIDs[II] = ID;
|
|
|
|
}
|
|
|
|
|
2012-10-10 07:05:51 +08:00
|
|
|
void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) {
|
|
|
|
MacroIDs[MI] = ID;
|
|
|
|
}
|
|
|
|
|
2010-08-21 00:03:59 +08:00
|
|
|
void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
|
2010-10-06 02:37:06 +08:00
|
|
|
// Always take the highest-numbered type index. This copes with an interesting
|
|
|
|
// case for chained AST writing where we schedule writing the type and then,
|
2010-10-21 11:16:25 +08:00
|
|
|
// later, deserialize the type from another AST. In this case, we want to
|
2010-10-06 02:37:06 +08:00
|
|
|
// keep the higher-numbered entry so that we can properly write it out to
|
|
|
|
// the AST file.
|
|
|
|
TypeIdx &StoredIdx = TypeIdxs[T];
|
|
|
|
if (Idx.getIndex() >= StoredIdx.getIndex())
|
|
|
|
StoredIdx = Idx;
|
2010-07-15 07:45:08 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
|
2010-08-05 01:20:04 +08:00
|
|
|
SelectorIDs[S] = ID;
|
|
|
|
}
|
2010-10-03 03:29:26 +08:00
|
|
|
|
2011-09-16 02:02:56 +08:00
|
|
|
void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID,
|
2010-10-03 03:29:26 +08:00
|
|
|
MacroDefinition *MD) {
|
2011-09-16 02:02:56 +08:00
|
|
|
assert(MacroDefinitions.find(MD) == MacroDefinitions.end());
|
2010-10-03 03:29:26 +08:00
|
|
|
MacroDefinitions[MD] = ID;
|
|
|
|
}
|
2010-10-25 01:26:50 +08:00
|
|
|
|
2011-12-03 01:30:13 +08:00
|
|
|
void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {
|
|
|
|
assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end());
|
|
|
|
SubmoduleIDs[Mod] = ID;
|
|
|
|
}
|
|
|
|
|
2012-10-10 07:05:51 +08:00
|
|
|
void ASTWriter::UndefinedMacro(MacroInfo *MI) {
|
|
|
|
MacroUpdates[MI].UndefLoc = MI->getUndefLoc();
|
|
|
|
}
|
|
|
|
|
2010-10-25 01:26:50 +08:00
|
|
|
void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
|
2011-10-07 14:10:15 +08:00
|
|
|
assert(D->isCompleteDefinition());
|
2011-09-17 08:05:03 +08:00
|
|
|
assert(!WritingAST && "Already writing the AST!");
|
2010-10-25 01:26:50 +08:00
|
|
|
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
|
|
|
|
// We are interested when a PCH decl is modified.
|
2011-09-10 07:01:35 +08:00
|
|
|
if (RD->isFromASTFile()) {
|
2010-10-25 01:26:50 +08:00
|
|
|
// A forward reference was mutated into a definition. Rewrite it.
|
|
|
|
// FIXME: This happens during template instantiation, should we
|
|
|
|
// have created a new definition decl instead ?
|
2010-10-28 15:38:45 +08:00
|
|
|
RewriteDecl(RD);
|
2010-10-25 01:26:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-10 07:05:51 +08:00
|
|
|
|
2010-10-28 15:38:51 +08:00
|
|
|
void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
|
2011-09-17 08:05:03 +08:00
|
|
|
assert(!WritingAST && "Already writing the AST!");
|
|
|
|
|
2010-10-28 15:38:51 +08:00
|
|
|
// TU and namespaces are handled elsewhere.
|
|
|
|
if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC))
|
|
|
|
return;
|
|
|
|
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile()))
|
2010-10-28 15:38:51 +08:00
|
|
|
return; // Not a source decl added to a DeclContext from PCH.
|
|
|
|
|
|
|
|
AddUpdatedDeclContext(DC);
|
2012-07-03 03:19:01 +08:00
|
|
|
UpdatingVisibleDecls.push_back(D);
|
2010-10-28 15:38:51 +08:00
|
|
|
}
|
2010-10-25 01:26:54 +08:00
|
|
|
|
|
|
|
void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {
|
2011-09-17 08:05:03 +08:00
|
|
|
assert(!WritingAST && "Already writing the AST!");
|
2010-10-25 01:26:54 +08:00
|
|
|
assert(D->isImplicit());
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!(!D->isFromASTFile() && RD->isFromASTFile()))
|
2010-10-25 01:26:54 +08:00
|
|
|
return; // Not a source member added to a class from PCH.
|
|
|
|
if (!isa<CXXMethodDecl>(D))
|
|
|
|
return; // We are interested in lazily declared implicit methods.
|
|
|
|
|
|
|
|
// A decl coming from PCH was modified.
|
2011-10-07 14:10:15 +08:00
|
|
|
assert(RD->isCompleteDefinition());
|
2010-10-25 01:26:54 +08:00
|
|
|
UpdateRecord &Record = DeclUpdates[RD];
|
|
|
|
Record.push_back(UPD_CXX_ADDED_IMPLICIT_MEMBER);
|
2011-09-17 08:05:03 +08:00
|
|
|
Record.push_back(reinterpret_cast<uint64_t>(D));
|
2010-10-25 01:26:54 +08:00
|
|
|
}
|
2010-10-28 15:38:42 +08:00
|
|
|
|
|
|
|
void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
|
|
|
|
const ClassTemplateSpecializationDecl *D) {
|
2010-10-28 15:38:47 +08:00
|
|
|
// The specializations set is kept in the canonical template.
|
2011-09-17 08:05:03 +08:00
|
|
|
assert(!WritingAST && "Already writing the AST!");
|
2010-10-28 15:38:47 +08:00
|
|
|
TD = TD->getCanonicalDecl();
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!(!D->isFromASTFile() && TD->isFromASTFile()))
|
2010-10-28 15:38:42 +08:00
|
|
|
return; // Not a source specialization added to a template from PCH.
|
|
|
|
|
|
|
|
UpdateRecord &Record = DeclUpdates[TD];
|
|
|
|
Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
|
2011-09-17 08:05:03 +08:00
|
|
|
Record.push_back(reinterpret_cast<uint64_t>(D));
|
2010-10-28 15:38:42 +08:00
|
|
|
}
|
2010-11-30 14:16:57 +08:00
|
|
|
|
2011-04-14 22:07:59 +08:00
|
|
|
void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
|
|
|
|
const FunctionDecl *D) {
|
|
|
|
// The specializations set is kept in the canonical template.
|
2011-09-17 08:05:03 +08:00
|
|
|
assert(!WritingAST && "Already writing the AST!");
|
2011-04-14 22:07:59 +08:00
|
|
|
TD = TD->getCanonicalDecl();
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!(!D->isFromASTFile() && TD->isFromASTFile()))
|
2011-04-14 22:07:59 +08:00
|
|
|
return; // Not a source specialization added to a template from PCH.
|
|
|
|
|
|
|
|
UpdateRecord &Record = DeclUpdates[TD];
|
|
|
|
Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
|
2011-09-17 08:05:03 +08:00
|
|
|
Record.push_back(reinterpret_cast<uint64_t>(D));
|
2011-04-14 22:07:59 +08:00
|
|
|
}
|
|
|
|
|
2011-04-25 00:28:06 +08:00
|
|
|
void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
|
2011-09-17 08:05:03 +08:00
|
|
|
assert(!WritingAST && "Already writing the AST!");
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!D->isFromASTFile())
|
2011-04-25 00:28:06 +08:00
|
|
|
return; // Declaration not imported from PCH.
|
|
|
|
|
|
|
|
// Implicit decl from a PCH was defined.
|
|
|
|
// FIXME: Should implicit definition be a separate FunctionDecl?
|
|
|
|
RewriteDecl(D);
|
|
|
|
}
|
|
|
|
|
2011-04-29 16:19:30 +08:00
|
|
|
void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
|
2011-09-17 08:05:03 +08:00
|
|
|
assert(!WritingAST && "Already writing the AST!");
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!D->isFromASTFile())
|
2011-04-29 16:19:30 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Since the actual instantiation is delayed, this really means that we need
|
|
|
|
// to update the instantiation location.
|
|
|
|
UpdateRecord &Record = DeclUpdates[D];
|
|
|
|
Record.push_back(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER);
|
|
|
|
AddSourceLocation(
|
|
|
|
D->getMemberSpecializationInfo()->getPointOfInstantiation(), Record);
|
|
|
|
}
|
|
|
|
|
2011-09-01 08:58:55 +08:00
|
|
|
void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
|
|
|
|
const ObjCInterfaceDecl *IFD) {
|
2011-09-17 08:05:03 +08:00
|
|
|
assert(!WritingAST && "Already writing the AST!");
|
2011-09-10 07:01:35 +08:00
|
|
|
if (!IFD->isFromASTFile())
|
2011-09-01 08:58:55 +08:00
|
|
|
return; // Declaration not imported from PCH.
|
2012-01-27 09:47:08 +08:00
|
|
|
|
|
|
|
assert(IFD->getDefinition() && "Category on a class without a definition?");
|
|
|
|
ObjCClassesWithCategories.insert(
|
|
|
|
const_cast<ObjCInterfaceDecl *>(IFD->getDefinition()));
|
2011-09-01 08:58:55 +08:00
|
|
|
}
|
2011-11-13 05:07:46 +08:00
|
|
|
|
2011-11-13 05:07:52 +08:00
|
|
|
|
2011-11-14 12:52:29 +08:00
|
|
|
void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
|
|
|
|
const ObjCPropertyDecl *OrigProp,
|
|
|
|
const ObjCCategoryDecl *ClassExt) {
|
|
|
|
const ObjCInterfaceDecl *D = ClassExt->getClassInterface();
|
|
|
|
if (!D)
|
|
|
|
return;
|
|
|
|
|
|
|
|
assert(!WritingAST && "Already writing the AST!");
|
|
|
|
if (!D->isFromASTFile())
|
|
|
|
return; // Declaration not imported from PCH.
|
|
|
|
|
|
|
|
RewriteDecl(D);
|
|
|
|
}
|