Skip to content

Commit 62e576b

Browse files
authored
[clang] Make the entire CompilerInvocation ref-counted (#65647)
This enables making the whole `CompilerInvocation` more efficient through copy-on-write.
1 parent 7fda1b7 commit 62e576b

File tree

2 files changed

+133
-147
lines changed

2 files changed

+133
-147
lines changed

clang/include/clang/Frontend/CompilerInvocation.h

Lines changed: 63 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,12 @@ bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args,
6666
DiagnosticsEngine *Diags = nullptr,
6767
bool DefaultDiagColor = true);
6868

69-
/// The base class of CompilerInvocation with reference semantics.
70-
///
71-
/// This class stores option objects behind reference-counted pointers. This is
72-
/// useful for clients that want to keep some option object around even after
73-
/// CompilerInvocation gets destroyed, without making a copy.
74-
///
75-
/// This is a separate class so that we can implement the copy constructor and
76-
/// assignment here and leave them defaulted in the rest of CompilerInvocation.
77-
class CompilerInvocationRefBase {
78-
public:
69+
/// The base class of CompilerInvocation. It keeps individual option objects
70+
/// behind reference-counted pointers, which is useful for clients that want to
71+
/// keep select option objects alive (even after CompilerInvocation gets
72+
/// destroyed) without making a copy.
73+
class CompilerInvocationBase {
74+
protected:
7975
/// Options controlling the language variant.
8076
std::shared_ptr<LangOptions> LangOpts;
8177

@@ -86,103 +82,71 @@ class CompilerInvocationRefBase {
8682
IntrusiveRefCntPtr<DiagnosticOptions> DiagnosticOpts;
8783

8884
/// Options controlling the \#include directive.
89-
std::shared_ptr<HeaderSearchOptions> HeaderSearchOpts;
85+
std::shared_ptr<HeaderSearchOptions> HSOpts;
9086

9187
/// Options controlling the preprocessor (aside from \#include handling).
92-
std::shared_ptr<PreprocessorOptions> PreprocessorOpts;
88+
std::shared_ptr<PreprocessorOptions> PPOpts;
9389

9490
/// Options controlling the static analyzer.
9591
AnalyzerOptionsRef AnalyzerOpts;
9692

97-
CompilerInvocationRefBase();
98-
CompilerInvocationRefBase(const CompilerInvocationRefBase &X);
99-
CompilerInvocationRefBase(CompilerInvocationRefBase &&X);
100-
CompilerInvocationRefBase &operator=(CompilerInvocationRefBase X);
101-
CompilerInvocationRefBase &operator=(CompilerInvocationRefBase &&X);
102-
~CompilerInvocationRefBase();
103-
104-
LangOptions &getLangOpts() { return *LangOpts; }
105-
const LangOptions &getLangOpts() const { return *LangOpts; }
106-
107-
TargetOptions &getTargetOpts() { return *TargetOpts.get(); }
108-
const TargetOptions &getTargetOpts() const { return *TargetOpts.get(); }
109-
110-
DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
111-
112-
HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; }
113-
114-
const HeaderSearchOptions &getHeaderSearchOpts() const {
115-
return *HeaderSearchOpts;
116-
}
117-
118-
std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() const {
119-
return HeaderSearchOpts;
120-
}
121-
122-
std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() {
123-
return PreprocessorOpts;
124-
}
125-
126-
PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; }
127-
128-
const PreprocessorOptions &getPreprocessorOpts() const {
129-
return *PreprocessorOpts;
130-
}
131-
132-
AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; }
133-
const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; }
134-
};
135-
136-
/// The base class of CompilerInvocation with value semantics.
137-
class CompilerInvocationValueBase {
138-
protected:
139-
MigratorOptions MigratorOpts;
93+
std::shared_ptr<MigratorOptions> MigratorOpts;
14094

14195
/// Options controlling IRgen and the backend.
142-
CodeGenOptions CodeGenOpts;
143-
144-
/// Options controlling dependency output.
145-
DependencyOutputOptions DependencyOutputOpts;
96+
std::shared_ptr<CodeGenOptions> CodeGenOpts;
14697

14798
/// Options controlling file system operations.
148-
FileSystemOptions FileSystemOpts;
99+
std::shared_ptr<FileSystemOptions> FSOpts;
149100

150101
/// Options controlling the frontend itself.
151-
FrontendOptions FrontendOpts;
102+
std::shared_ptr<FrontendOptions> FrontendOpts;
103+
104+
/// Options controlling dependency output.
105+
std::shared_ptr<DependencyOutputOptions> DependencyOutputOpts;
152106

153107
/// Options controlling preprocessed output.
154-
PreprocessorOutputOptions PreprocessorOutputOpts;
108+
std::shared_ptr<PreprocessorOutputOptions> PreprocessorOutputOpts;
155109

156110
public:
157-
MigratorOptions &getMigratorOpts() { return MigratorOpts; }
158-
const MigratorOptions &getMigratorOpts() const { return MigratorOpts; }
159-
160-
CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; }
161-
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
162-
163-
DependencyOutputOptions &getDependencyOutputOpts() {
164-
return DependencyOutputOpts;
165-
}
111+
CompilerInvocationBase();
112+
CompilerInvocationBase(const CompilerInvocationBase &X) { operator=(X); }
113+
CompilerInvocationBase(CompilerInvocationBase &&X) = default;
114+
CompilerInvocationBase &operator=(const CompilerInvocationBase &X);
115+
CompilerInvocationBase &operator=(CompilerInvocationBase &&X) = default;
116+
~CompilerInvocationBase() = default;
166117

118+
const LangOptions &getLangOpts() const { return *LangOpts; }
119+
const TargetOptions &getTargetOpts() const { return *TargetOpts; }
120+
const DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
121+
const HeaderSearchOptions &getHeaderSearchOpts() const { return *HSOpts; }
122+
const PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; }
123+
const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; }
124+
const MigratorOptions &getMigratorOpts() const { return *MigratorOpts; }
125+
const CodeGenOptions &getCodeGenOpts() const { return *CodeGenOpts; }
126+
const FileSystemOptions &getFileSystemOpts() const { return *FSOpts; }
127+
const FrontendOptions &getFrontendOpts() const { return *FrontendOpts; }
167128
const DependencyOutputOptions &getDependencyOutputOpts() const {
168-
return DependencyOutputOpts;
129+
return *DependencyOutputOpts;
169130
}
170-
171-
FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
172-
173-
const FileSystemOptions &getFileSystemOpts() const {
174-
return FileSystemOpts;
131+
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
132+
return *PreprocessorOutputOpts;
175133
}
176134

177-
FrontendOptions &getFrontendOpts() { return FrontendOpts; }
178-
const FrontendOptions &getFrontendOpts() const { return FrontendOpts; }
179-
180-
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
181-
return PreprocessorOutputOpts;
135+
LangOptions &getLangOpts() { return *LangOpts; }
136+
TargetOptions &getTargetOpts() { return *TargetOpts; }
137+
DiagnosticOptions &getDiagnosticOpts() { return *DiagnosticOpts; }
138+
HeaderSearchOptions &getHeaderSearchOpts() { return *HSOpts; }
139+
PreprocessorOptions &getPreprocessorOpts() { return *PPOpts; }
140+
AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; }
141+
MigratorOptions &getMigratorOpts() { return *MigratorOpts; }
142+
CodeGenOptions &getCodeGenOpts() { return *CodeGenOpts; }
143+
FileSystemOptions &getFileSystemOpts() { return *FSOpts; }
144+
FrontendOptions &getFrontendOpts() { return *FrontendOpts; }
145+
DependencyOutputOptions &getDependencyOutputOpts() {
146+
return *DependencyOutputOpts;
182147
}
183-
184-
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
185-
return PreprocessorOutputOpts;
148+
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
149+
return *PreprocessorOutputOpts;
186150
}
187151
};
188152

@@ -191,9 +155,21 @@ class CompilerInvocationValueBase {
191155
/// This class is designed to represent an abstract "invocation" of the
192156
/// compiler, including data such as the include paths, the code generation
193157
/// options, the warning flags, and so on.
194-
class CompilerInvocation : public CompilerInvocationRefBase,
195-
public CompilerInvocationValueBase {
158+
class CompilerInvocation : public CompilerInvocationBase {
196159
public:
160+
/// Base class internals.
161+
/// @{
162+
using CompilerInvocationBase::LangOpts;
163+
using CompilerInvocationBase::TargetOpts;
164+
using CompilerInvocationBase::DiagnosticOpts;
165+
std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() {
166+
return HSOpts;
167+
}
168+
std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() {
169+
return PPOpts;
170+
}
171+
/// @}
172+
197173
/// Create a compiler invocation from a list of input options.
198174
/// \returns true on success.
199175
///

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 70 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -126,40 +126,49 @@ static Expected<std::optional<uint32_t>> parseToleranceOption(StringRef Arg) {
126126
// Initialization.
127127
//===----------------------------------------------------------------------===//
128128

129-
CompilerInvocationRefBase::CompilerInvocationRefBase()
130-
: LangOpts(new LangOptions()), TargetOpts(new TargetOptions()),
131-
DiagnosticOpts(new DiagnosticOptions()),
132-
HeaderSearchOpts(new HeaderSearchOptions()),
133-
PreprocessorOpts(new PreprocessorOptions()),
134-
AnalyzerOpts(new AnalyzerOptions()) {}
135-
136-
CompilerInvocationRefBase::CompilerInvocationRefBase(
137-
const CompilerInvocationRefBase &X)
138-
: LangOpts(new LangOptions(X.getLangOpts())),
139-
TargetOpts(new TargetOptions(X.getTargetOpts())),
140-
DiagnosticOpts(new DiagnosticOptions(X.getDiagnosticOpts())),
141-
HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())),
142-
PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())),
143-
AnalyzerOpts(new AnalyzerOptions(X.getAnalyzerOpts())) {}
144-
145-
CompilerInvocationRefBase::CompilerInvocationRefBase(
146-
CompilerInvocationRefBase &&X) = default;
147-
148-
CompilerInvocationRefBase &
149-
CompilerInvocationRefBase::operator=(CompilerInvocationRefBase X) {
150-
LangOpts.swap(X.LangOpts);
151-
TargetOpts.swap(X.TargetOpts);
152-
DiagnosticOpts.swap(X.DiagnosticOpts);
153-
HeaderSearchOpts.swap(X.HeaderSearchOpts);
154-
PreprocessorOpts.swap(X.PreprocessorOpts);
155-
AnalyzerOpts.swap(X.AnalyzerOpts);
156-
return *this;
129+
namespace {
130+
template <class T> std::shared_ptr<T> make_shared_copy(const T &X) {
131+
return std::make_shared<T>(X);
157132
}
158133

159-
CompilerInvocationRefBase &
160-
CompilerInvocationRefBase::operator=(CompilerInvocationRefBase &&X) = default;
161-
162-
CompilerInvocationRefBase::~CompilerInvocationRefBase() = default;
134+
template <class T>
135+
llvm::IntrusiveRefCntPtr<T> makeIntrusiveRefCntCopy(const T &X) {
136+
return llvm::makeIntrusiveRefCnt<T>(X);
137+
}
138+
} // namespace
139+
140+
CompilerInvocationBase::CompilerInvocationBase()
141+
: LangOpts(std::make_shared<LangOptions>()),
142+
TargetOpts(std::make_shared<TargetOptions>()),
143+
DiagnosticOpts(llvm::makeIntrusiveRefCnt<DiagnosticOptions>()),
144+
HSOpts(std::make_shared<HeaderSearchOptions>()),
145+
PPOpts(std::make_shared<PreprocessorOptions>()),
146+
AnalyzerOpts(llvm::makeIntrusiveRefCnt<AnalyzerOptions>()),
147+
MigratorOpts(std::make_shared<MigratorOptions>()),
148+
CodeGenOpts(std::make_shared<CodeGenOptions>()),
149+
FSOpts(std::make_shared<FileSystemOptions>()),
150+
FrontendOpts(std::make_shared<FrontendOptions>()),
151+
DependencyOutputOpts(std::make_shared<DependencyOutputOptions>()),
152+
PreprocessorOutputOpts(std::make_shared<PreprocessorOutputOptions>()) {}
153+
154+
CompilerInvocationBase &
155+
CompilerInvocationBase::operator=(const CompilerInvocationBase &X) {
156+
if (this != &X) {
157+
LangOpts = make_shared_copy(X.getLangOpts());
158+
TargetOpts = make_shared_copy(X.getTargetOpts());
159+
DiagnosticOpts = makeIntrusiveRefCntCopy(X.getDiagnosticOpts());
160+
HSOpts = make_shared_copy(X.getHeaderSearchOpts());
161+
PPOpts = make_shared_copy(X.getPreprocessorOpts());
162+
AnalyzerOpts = makeIntrusiveRefCntCopy(X.getAnalyzerOpts());
163+
MigratorOpts = make_shared_copy(X.getMigratorOpts());
164+
CodeGenOpts = make_shared_copy(X.getCodeGenOpts());
165+
FSOpts = make_shared_copy(X.getFileSystemOpts());
166+
FrontendOpts = make_shared_copy(X.getFrontendOpts());
167+
DependencyOutputOpts = make_shared_copy(X.getDependencyOutputOpts());
168+
PreprocessorOutputOpts = make_shared_copy(X.getPreprocessorOutputOpts());
169+
}
170+
return *this;
171+
}
163172

164173
//===----------------------------------------------------------------------===//
165174
// Normalizers
@@ -838,7 +847,7 @@ static void getAllNoBuiltinFuncValues(ArgList &Args,
838847
Funcs.insert(Funcs.end(), Values.begin(), BuiltinEnd);
839848
}
840849

841-
static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
850+
static void GenerateAnalyzerArgs(const AnalyzerOptions &Opts,
842851
ArgumentConsumer Consumer) {
843852
const AnalyzerOptions *AnalyzerOpts = &Opts;
844853

@@ -2917,7 +2926,7 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
29172926
return Driver::GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR);
29182927
}
29192928

2920-
static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
2929+
static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
29212930
ArgumentConsumer Consumer) {
29222931
const HeaderSearchOptions *HeaderSearchOpts = &Opts;
29232932
#define HEADER_SEARCH_OPTION_WITH_MARSHALLING(...) \
@@ -4103,12 +4112,12 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
41034112
llvm_unreachable("invalid frontend action");
41044113
}
41054114

4106-
static void GeneratePreprocessorArgs(PreprocessorOptions &Opts,
4115+
static void GeneratePreprocessorArgs(const PreprocessorOptions &Opts,
41074116
ArgumentConsumer Consumer,
41084117
const LangOptions &LangOpts,
41094118
const FrontendOptions &FrontendOpts,
41104119
const CodeGenOptions &CodeGenOpts) {
4111-
PreprocessorOptions *PreprocessorOpts = &Opts;
4120+
const PreprocessorOptions *PreprocessorOpts = &Opts;
41124121

41134122
#define PREPROCESSOR_OPTION_WITH_MARSHALLING(...) \
41144123
GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
@@ -4514,15 +4523,15 @@ std::string CompilerInvocation::getModuleHash() const {
45144523
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
45154524
#include "clang/Basic/LangOptions.def"
45164525

4517-
HBuilder.addRange(LangOpts->ModuleFeatures);
4526+
HBuilder.addRange(getLangOpts().ModuleFeatures);
45184527

4519-
HBuilder.add(LangOpts->ObjCRuntime);
4520-
HBuilder.addRange(LangOpts->CommentOpts.BlockCommandNames);
4528+
HBuilder.add(getLangOpts().ObjCRuntime);
4529+
HBuilder.addRange(getLangOpts().CommentOpts.BlockCommandNames);
45214530

45224531
// Extend the signature with the target options.
4523-
HBuilder.add(TargetOpts->Triple, TargetOpts->CPU, TargetOpts->TuneCPU,
4524-
TargetOpts->ABI);
4525-
HBuilder.addRange(TargetOpts->FeaturesAsWritten);
4532+
HBuilder.add(getTargetOpts().Triple, getTargetOpts().CPU,
4533+
getTargetOpts().TuneCPU, getTargetOpts().ABI);
4534+
HBuilder.addRange(getTargetOpts().FeaturesAsWritten);
45264535

45274536
// Extend the signature with preprocessor options.
45284537
const PreprocessorOptions &ppOpts = getPreprocessorOpts();
@@ -4577,7 +4586,7 @@ std::string CompilerInvocation::getModuleHash() const {
45774586

45784587
// Extend the signature with the enabled sanitizers, if at least one is
45794588
// enabled. Sanitizers which cannot affect AST generation aren't hashed.
4580-
SanitizerSet SanHash = LangOpts->Sanitize;
4589+
SanitizerSet SanHash = getLangOpts().Sanitize;
45814590
SanHash.clear(getPPTransparentSanitizers());
45824591
if (!SanHash.empty())
45834592
HBuilder.add(SanHash.Mask);
@@ -4590,23 +4599,24 @@ std::string CompilerInvocation::getModuleHash() const {
45904599

45914600
void CompilerInvocation::generateCC1CommandLine(
45924601
ArgumentConsumer Consumer) const {
4593-
llvm::Triple T(TargetOpts->Triple);
4594-
4595-
GenerateFileSystemArgs(FileSystemOpts, Consumer);
4596-
GenerateMigratorArgs(MigratorOpts, Consumer);
4597-
GenerateAnalyzerArgs(*AnalyzerOpts, Consumer);
4598-
GenerateDiagnosticArgs(*DiagnosticOpts, Consumer, false);
4599-
GenerateFrontendArgs(FrontendOpts, Consumer, LangOpts->IsHeaderFile);
4600-
GenerateTargetArgs(*TargetOpts, Consumer);
4601-
GenerateHeaderSearchArgs(*HeaderSearchOpts, Consumer);
4602-
GenerateLangArgs(*LangOpts, Consumer, T, FrontendOpts.DashX);
4603-
GenerateCodeGenArgs(CodeGenOpts, Consumer, T, FrontendOpts.OutputFile,
4604-
&*LangOpts);
4605-
GeneratePreprocessorArgs(*PreprocessorOpts, Consumer, *LangOpts, FrontendOpts,
4606-
CodeGenOpts);
4607-
GeneratePreprocessorOutputArgs(PreprocessorOutputOpts, Consumer,
4608-
FrontendOpts.ProgramAction);
4609-
GenerateDependencyOutputArgs(DependencyOutputOpts, Consumer);
4602+
llvm::Triple T(getTargetOpts().Triple);
4603+
4604+
GenerateFileSystemArgs(getFileSystemOpts(), Consumer);
4605+
GenerateMigratorArgs(getMigratorOpts(), Consumer);
4606+
GenerateAnalyzerArgs(getAnalyzerOpts(), Consumer);
4607+
GenerateDiagnosticArgs(getDiagnosticOpts(), Consumer,
4608+
/*DefaultDiagColor=*/false);
4609+
GenerateFrontendArgs(getFrontendOpts(), Consumer, getLangOpts().IsHeaderFile);
4610+
GenerateTargetArgs(getTargetOpts(), Consumer);
4611+
GenerateHeaderSearchArgs(getHeaderSearchOpts(), Consumer);
4612+
GenerateLangArgs(getLangOpts(), Consumer, T, getFrontendOpts().DashX);
4613+
GenerateCodeGenArgs(getCodeGenOpts(), Consumer, T,
4614+
getFrontendOpts().OutputFile, &getLangOpts());
4615+
GeneratePreprocessorArgs(getPreprocessorOpts(), Consumer, getLangOpts(),
4616+
getFrontendOpts(), getCodeGenOpts());
4617+
GeneratePreprocessorOutputArgs(getPreprocessorOutputOpts(), Consumer,
4618+
getFrontendOpts().ProgramAction);
4619+
GenerateDependencyOutputArgs(getDependencyOutputOpts(), Consumer);
46104620
}
46114621

46124622
std::vector<std::string> CompilerInvocation::getCC1CommandLine() const {

0 commit comments

Comments
 (0)