Skip to content

Commit 5cef6f3

Browse files
authored
[llvm][mustache] Use BumpPtrAllocator to save ASTNodes (#159194)
We make the Mustache ASTNodes usable in the arena by first removing all of the memory owning data structures, like std::vector, std::unique_ptr, and SmallVector. We use standard LLVM list types to hold this data instead, and make use of a UniqueStringSaver to hold the various templates strings. Additionally, update clang-doc APIs to use the new interfaces. Future work can make better use of Twine interfaces to help avoid any intermediate copies or allocations.
1 parent 8523c6a commit 5cef6f3

File tree

6 files changed

+739
-256
lines changed

6 files changed

+739
-256
lines changed

clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,22 @@ class MustacheHTMLGenerator : public Generator {
4646
const ClangDocContext &CDCtx) override;
4747
};
4848

49-
class MustacheTemplateFile : public Template {
49+
class MustacheTemplateFile {
50+
BumpPtrAllocator Allocator;
51+
StringSaver Saver;
52+
MustacheContext Ctx;
53+
Template T;
54+
std::unique_ptr<MemoryBuffer> Buffer;
55+
5056
public:
5157
static Expected<std::unique_ptr<MustacheTemplateFile>>
5258
createMustacheFile(StringRef FileName) {
5359
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
5460
MemoryBuffer::getFile(FileName);
5561
if (auto EC = BufferOrError.getError())
5662
return createFileOpenError(FileName, EC);
57-
58-
std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOrError.get());
59-
StringRef FileContent = Buffer->getBuffer();
60-
return std::make_unique<MustacheTemplateFile>(FileContent);
63+
return std::make_unique<MustacheTemplateFile>(
64+
std::move(BufferOrError.get()));
6165
}
6266

6367
Error registerPartialFile(StringRef Name, StringRef FileName) {
@@ -68,11 +72,15 @@ class MustacheTemplateFile : public Template {
6872

6973
std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOrError.get());
7074
StringRef FileContent = Buffer->getBuffer();
71-
registerPartial(Name.str(), FileContent.str());
75+
T.registerPartial(Name.str(), FileContent.str());
7276
return Error::success();
7377
}
7478

75-
MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
79+
void render(json::Value &V, raw_ostream &OS) { T.render(V, OS); }
80+
81+
MustacheTemplateFile(std::unique_ptr<MemoryBuffer> &&B)
82+
: Saver(Allocator), Ctx(Allocator, Saver), T(B->getBuffer(), Ctx),
83+
Buffer(std::move(B)) {}
7684
};
7785

7886
static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;

llvm/benchmarks/Mustache.cpp

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
static const std::string LongHtmlString = [] {
99
std::string S;
1010
S.reserve(500000);
11-
for (int i = 0; i < 50000; ++i) {
11+
for (int Idx = 0; Idx < 50000; ++Idx) {
1212
S += "<script>alert('xss');</script>";
1313
}
1414
return S;
@@ -153,7 +153,11 @@ static const std::string LargeOutputStringTemplate = "{{long_string}}";
153153
// syntaxes.
154154
static void BM_Mustache_StringRendering(benchmark::State &state,
155155
const std::string &TplStr) {
156-
llvm::mustache::Template Tpl(TplStr);
156+
llvm::BumpPtrAllocator Allocator;
157+
llvm::StringSaver Saver(Allocator);
158+
llvm::mustache::MustacheContext Ctx(Allocator, Saver);
159+
160+
llvm::mustache::Template Tpl(TplStr, Ctx);
157161
llvm::json::Value Data =
158162
llvm::json::Object({{"content", llvm::json::Value(LongHtmlString)}});
159163
for (auto _ : state) {
@@ -172,7 +176,11 @@ BENCHMARK_CAPTURE(BM_Mustache_StringRendering, Unescaped_Ampersand,
172176
// Tests the "hot render" cost of repeatedly traversing a deep and wide
173177
// JSON object.
174178
static void BM_Mustache_DeepTraversal(benchmark::State &state) {
175-
llvm::mustache::Template Tpl(DeepTraversalTemplate);
179+
llvm::BumpPtrAllocator Allocator;
180+
llvm::StringSaver Saver(Allocator);
181+
llvm::mustache::MustacheContext Ctx(Allocator, Saver);
182+
183+
llvm::mustache::Template Tpl(DeepTraversalTemplate, Ctx);
176184
for (auto _ : state) {
177185
std::string Result;
178186
llvm::raw_string_ostream OS(Result);
@@ -184,7 +192,12 @@ BENCHMARK(BM_Mustache_DeepTraversal);
184192

185193
// Tests the "hot render" cost of pushing and popping a deep context stack.
186194
static void BM_Mustache_DeeplyNestedRendering(benchmark::State &state) {
187-
llvm::mustache::Template Tpl(DeeplyNestedRenderingTemplate);
195+
196+
llvm::BumpPtrAllocator Allocator;
197+
llvm::StringSaver Saver(Allocator);
198+
llvm::mustache::MustacheContext Ctx(Allocator, Saver);
199+
200+
llvm::mustache::Template Tpl(DeeplyNestedRenderingTemplate, Ctx);
188201
for (auto _ : state) {
189202
std::string Result;
190203
llvm::raw_string_ostream OS(Result);
@@ -197,7 +210,11 @@ BENCHMARK(BM_Mustache_DeeplyNestedRendering);
197210
// Tests the performance of the loop logic when iterating over a huge number of
198211
// items.
199212
static void BM_Mustache_HugeArrayIteration(benchmark::State &state) {
200-
llvm::mustache::Template Tpl(HugeArrayIterationTemplate);
213+
llvm::BumpPtrAllocator Allocator;
214+
llvm::StringSaver Saver(Allocator);
215+
llvm::mustache::MustacheContext Ctx(Allocator, Saver);
216+
217+
llvm::mustache::Template Tpl(HugeArrayIterationTemplate, Ctx);
201218
for (auto _ : state) {
202219
std::string Result;
203220
llvm::raw_string_ostream OS(Result);
@@ -209,25 +226,37 @@ BENCHMARK(BM_Mustache_HugeArrayIteration);
209226

210227
// Tests the performance of the parser on a large, "wide" template.
211228
static void BM_Mustache_ComplexTemplateParsing(benchmark::State &state) {
229+
llvm::BumpPtrAllocator Allocator;
230+
llvm::StringSaver Saver(Allocator);
231+
llvm::mustache::MustacheContext Ctx(Allocator, Saver);
232+
212233
for (auto _ : state) {
213-
llvm::mustache::Template Tpl(ComplexTemplateParsingTemplate);
234+
llvm::mustache::Template Tpl(ComplexTemplateParsingTemplate, Ctx);
214235
benchmark::DoNotOptimize(Tpl);
215236
}
216237
}
217238
BENCHMARK(BM_Mustache_ComplexTemplateParsing);
218239

219240
// Tests the performance of the parser on a small, "deep" template.
220241
static void BM_Mustache_SmallTemplateParsing(benchmark::State &state) {
242+
llvm::BumpPtrAllocator Allocator;
243+
llvm::StringSaver Saver(Allocator);
244+
llvm::mustache::MustacheContext Ctx(Allocator, Saver);
245+
221246
for (auto _ : state) {
222-
llvm::mustache::Template Tpl(SmallTemplateParsingTemplate);
247+
llvm::mustache::Template Tpl(SmallTemplateParsingTemplate, Ctx);
223248
benchmark::DoNotOptimize(Tpl);
224249
}
225250
}
226251
BENCHMARK(BM_Mustache_SmallTemplateParsing);
227252

228253
// Tests the performance of rendering a template that includes a partial.
229254
static void BM_Mustache_PartialsRendering(benchmark::State &state) {
230-
llvm::mustache::Template Tpl(ComplexPartialTemplate);
255+
llvm::BumpPtrAllocator Allocator;
256+
llvm::StringSaver Saver(Allocator);
257+
llvm::mustache::MustacheContext Ctx(Allocator, Saver);
258+
259+
llvm::mustache::Template Tpl(ComplexPartialTemplate, Ctx);
231260
Tpl.registerPartial("item_partial", ItemPartialTemplate);
232261
llvm::json::Value Data = HugeArrayData;
233262

@@ -243,7 +272,11 @@ BENCHMARK(BM_Mustache_PartialsRendering);
243272
// Tests the performance of the underlying buffer management when generating a
244273
// very large output.
245274
static void BM_Mustache_LargeOutputString(benchmark::State &state) {
246-
llvm::mustache::Template Tpl(LargeOutputStringTemplate);
275+
llvm::BumpPtrAllocator Allocator;
276+
llvm::StringSaver Saver(Allocator);
277+
llvm::mustache::MustacheContext Ctx(Allocator, Saver);
278+
279+
llvm::mustache::Template Tpl(LargeOutputStringTemplate, Ctx);
247280
for (auto _ : state) {
248281
std::string Result;
249282
llvm::raw_string_ostream OS(Result);

llvm/include/llvm/Support/Mustache.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171

7272
#include "Error.h"
7373
#include "llvm/ADT/StringMap.h"
74+
#include "llvm/ADT/ilist.h"
75+
#include "llvm/ADT/ilist_node.h"
7476
#include "llvm/Support/Allocator.h"
7577
#include "llvm/Support/Compiler.h"
7678
#include "llvm/Support/JSON.h"
@@ -84,10 +86,15 @@ using Lambda = std::function<llvm::json::Value()>;
8486
using SectionLambda = std::function<llvm::json::Value(std::string)>;
8587

8688
class ASTNode;
87-
using AstPtr = std::unique_ptr<ASTNode>;
89+
using AstPtr = ASTNode *;
8890
using EscapeMap = DenseMap<char, std::string>;
91+
using ASTNodeList = iplist<ASTNode>;
8992

9093
struct MustacheContext {
94+
MustacheContext(BumpPtrAllocator &Allocator, StringSaver &Saver)
95+
: Allocator(Allocator), Saver(Saver) {}
96+
BumpPtrAllocator &Allocator;
97+
StringSaver &Saver;
9198
StringMap<AstPtr> Partials;
9299
StringMap<Lambda> Lambdas;
93100
StringMap<SectionLambda> SectionLambdas;
@@ -98,7 +105,7 @@ struct MustacheContext {
98105
// and Lambdas that are registered with it.
99106
class Template {
100107
public:
101-
LLVM_ABI Template(StringRef TemplateStr);
108+
LLVM_ABI Template(StringRef TemplateStr, MustacheContext &Ctx);
102109

103110
Template(const Template &) = delete;
104111

@@ -110,7 +117,7 @@ class Template {
110117
// type.
111118
LLVM_ABI ~Template();
112119

113-
LLVM_ABI Template &operator=(Template &&Other) noexcept;
120+
Template &operator=(Template &&) = delete;
114121

115122
LLVM_ABI void render(const llvm::json::Value &Data, llvm::raw_ostream &OS);
116123

@@ -126,7 +133,7 @@ class Template {
126133
LLVM_ABI void overrideEscapeCharacters(DenseMap<char, std::string> Escapes);
127134

128135
private:
129-
MustacheContext Ctx;
136+
MustacheContext &Ctx;
130137
AstPtr Tree;
131138
};
132139
} // namespace llvm::mustache

0 commit comments

Comments
 (0)