This is an archive of the discontinued LLVM Phabricator instance.

Don't use static variables in LambdaCapture
ClosedPublic

Authored by john.brawn on May 27 2016, 8:13 AM.

Details

Summary

When static variables are used in inline functions in header files anything that uses that function ends up with a reference to the variable. Because RecursiveASTVisitor uses the inline functions in LambdaCapture that use static variables any AST plugin that uses RecursiveASTVisitor, such as the PrintFunctionNames example, ends up with a reference to these variables. This is bad on Windows when building with MSVC with LLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON as variables used across a DLL boundary need to be explicitly dllimported in the DLL using them.

This patch avoids that by adjusting LambdaCapture to be similar to before r263921, with a capture of either 'this' or a VLA represented by a null Decl pointer in DeclAndBits with an extra flag added to the bits to distinguish between the two. This requires the use of an extra bit, and while Decl does happen to be sufficiently aligned to allow this it's done in a way that means PointerIntPair doesn't realise it and gives an assertion failure. Therefore I also adjust Decl slightly to use LLVM_ALIGNAS to allow this.

Diff Detail

Repository
rL LLVM

Event Timeline

john.brawn updated this revision to Diff 58787.May 27 2016, 8:13 AM
john.brawn retitled this revision from to Don't use static variables in LambdaCapture.
john.brawn updated this object.
john.brawn added reviewers: faisalv, rsmith, jyknight.
john.brawn set the repository for this revision to rL LLVM.
john.brawn added a subscriber: cfe-commits.
faisalv edited edge metadata.Jun 8 2016, 4:20 AM

Seems reasonable to me if we have the bit to spare. I wasn't a huge fan of the sentinel approach - but i appreciated Richard showing me that trick. I don't think I realized that Decl has to be aligned on an 8 byte boundary. I'm not too familiar with the alignment gymnastics - but I'm assuming you've given some thought to any existing pathological code that might break if the actual compile-time alignment of Decl itself is changed (since currently it seems to be that the alignment requirements are established at run-time and only through allocation via new (not that anyone would be creating Decls on the stack)) - and whether there are any consequences of relevance there...
Thanks!

I'm assuming you've given some thought to any existing pathological code that might break if the actual compile-time alignment of Decl itself is changed (since currently it seems to be that the alignment requirements are established at run-time and only through allocation via new (not that anyone would be creating Decls on the stack)) - and whether there are any consequences of relevance there...

I can't think of anything that could go wrong because of it. Reducing the alignment could cause problems, if there were things that check that the alignment is at least some value, but here I'm increasing it. Decl and all of its subclasses only have protected or private constructors and the only way to create them is through the various XYZDecl::Create methods which go through new so there should be no problem there either.

jyknight edited edge metadata.Jun 13 2016, 9:17 AM

This looks okay. The only downside: it will increase sizeof(Decl) on 32bit platforms, since the layout is:
vtable ptr (4)
NextInContextAndBits ptr (4)
DeclCtx ptr (4)
Loc int (4)
bitfield int (4)

Totaling 20 bytes, which will now be rounded up to 24 bytes. I don't know how others feel, but it seems probably fine to me? On 64-bit platforms, it's already 32 bytes, and that won't be affected.

This looks okay. The only downside: it will increase sizeof(Decl) on 32bit platforms, since the layout is:
vtable ptr (4)
NextInContextAndBits ptr (4)
DeclCtx ptr (4)
Loc int (4)
bitfield int (4)

Totaling 20 bytes, which will now be rounded up to 24 bytes. I don't know how others feel, but it seems probably fine to me? On 64-bit platforms, it's already 32 bytes, and that won't be affected.

I did an experiment compiling the top 5 largest llvm/clang source files with and without this patch and got the following numbers for "Maximum resident set size (kbytes)" reported by time -v

Source FileBeforeAfterChange
X86ISelLowering.cpp679824 +/- 28679897 +/- 27173 (0.01%)
SemaDecl.cpp705379 +/- 440705590 +/- 77211 (0.03%)
SemaExpr.cpp950729 +/- 6910951654 +/- 5834925 (0.10%)
DAGCombiner.cpp443673 +/- 38443721 +/- 1648 (0.01%)
SemaDeclCXX.cpp850441 +/- 4531851891 +/- 50791450 (0.17%)

I think a <0.2% increase in memory usage is fine.

jyknight accepted this revision.Jun 15 2016, 6:38 AM
jyknight edited edge metadata.

Fine with me.

This revision is now accepted and ready to land.Jun 15 2016, 6:38 AM
This revision was automatically updated to reflect the committed changes.