[cfe-dev] Modular Codegen: Cross-module deserialization problem
David Blaikie via cfe-dev
cfe-dev at lists.llvm.org
Fri Feb 24 14:25:05 PST 2017
OK, sounds fair - so GetExternalDeclStmt needs at least a Deserializing
object to defer deserialization further. Does it also need a
SavedStreamPosition, do you think? I can't immediately think of how/why it
might, but they seemed to be paired in other places.
On Fri, Feb 24, 2017 at 2:22 PM Richard Smith <richard at metafoo.co.uk> wrote:
> On 24 February 2017 at 09:41, David Blaikie <dblaikie at gmail.com> wrote:
>
> I've spent a few days debugging/trying to understand the following, so I'm
> writing it all down in the hopes of getting it straight/clear and
> potentially getting some external perspective on what's going on, whether
> I've understood it correctly, and what might be a good way to solve it.
>
> Starting with this test case:
> foo.h:
> struct foo {};
> inline void e() { foo(); }
> bar.h:
> #include "foo.h"
> template <typename T>
> foo bar(foo &f) {
> return f;
> }
> void z() { (void)&bar<int>; }
>
> Build each into a separate module, run modular codegen on bar.pcm:
> clang-tot -cc1 -fmodules-codegen -xc++ -emit-module -fmodules \
> -fmodule-name=foo foo.cppmap -o foo.pcm
> clang-tot -cc1 -fmodules-codegen -xc++ -emit-module -fmodules \
> -fmodule-name=bar bar.cppmap -o bar.pcm -fmodule-file=foo.pcm
> clang-tot -c bar.pcm -o bar.o
>
> (I haven't fully understood why the use of 'foo' in foo.h is necessary,
> nor why 'bar' needs to be a template - those might provide some further
> insight about how this should/could work)
>
> This patch makes the failure a bit more visible/immediate:
> diff --git lib/Serialization/ASTReaderStmt.cpp
> lib/Serialization/ASTReaderStmt.cpp
> index b4718367d4..1fb48e9560 100644
> @@ -3903,7 +3904,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F)
> {
> ++NumStatementsRead;
>
> if (S && !IsStmtReference) {
> + auto X = Cursor.GetCurrentBitNo();
> Reader.Visit(S);
> + assert(X == Cursor.GetCurrentBitNo() && "Narf");
> StmtEntries[Cursor.GetCurrentBitNo()] = S;
> }
>
> This is layered on top of the modular codegen rewrite/refactor (to use a
> bit on function definitions, instead of to imply modular codegen from the
> Module object) and some other fixes. I'll include the full patch I'm
> working with.
>
> The sequence of relevant steps (as best as I can figure)
>
> 1. bar() body deserialization begins
> 2. bar module's DeclCursor is used, jumping to the start of the
> bar()'s definition
> 3. clang::ASTReader::ReadStmtFromStream iterates through Stmts in bar()
> no SavedStreamPosition nor Deserializing object here
> 4. deserializing the EXPR_CXX_CONSTRUCT gets interesting:
> 5. eventually involves deserializing foo(const foo&)
> 6. foo module's DeclCursor is used
> 7. foo module's DeclCursor is saved/preserved with a
> SavedStreamPosition
> 8. a ExternalASTSource::Deserializing context is started
> 9. the definition of foo(const foo&) (in the bar module) is
> deserialized
> 10. this definition is 'interesting' and added to the ASTReader's
> InterestingDecls
> 11. The end of the Deserializing context (8) is reached
> 1. In the non-modular-codegen case, DeclMustBeEmitted is not true
> for foo(const foo&) and it is shelved for lazy emission, end of story
> 12. In the modular-codegen case, foo(const foo&) in the bar module
> must be emitted (all inline functions (implicitly or explicitly) defined in
> a module are emitted weak, etc)
> 13. So foo(const foo&) is non-lazily deserialized and emitted
> 14. The bar module's DeclCursor is used for this, unprotected
> 15. execution eventually gets back to the deserialization of bar() -
> and the DeclCursor it's using is out of position -> badness.
>
> Maybe there's a better way to provide this timeline, I'm not sure -
> hopefully it makes sense.
>
> Essentially the way ASTReader::ReadDeclRecord (started in (5) that
> contains the SavedStreamPosition and Deserializing context) seems to assume
> that the only things that will be non-lazily deserialized will come from
> the same module. Modular codegen breaks that invariant at the moment (well,
> with the patch provided).
>
> I did try SavedStreamPosition-protecting the call from 3->4 (specifically
> the "Visit(Expr)" call in ReadStmtFromStream) though still hit some
> crashes. Maybe that's the right path to go down still, but need to do more?
>
> When I tried to copy the DeclCursor in ReadStmtFromStream that actually
> broke things pretty significantly (compile errors on valid code even
> without modular codegen enabled). But I don't know much about the cursors -
> evidently more than only an efficiency concern, I guess the non-offset
> state in the copy of the cursor changes and so the original DeclCursor
> isn't updated, etc. (I wonder about splitting these cursors into a shared
> state + offset, share the state with shared_ptr and make it cheap to copy
> the actual offset state around so there's less reason to risk these sharing
> situations & all the SavedStreamPosition protection that requires).
>
> Long & short of it: What should I do here? What're the likely goals I
> should be trying to move the code towards, if any?
>
>
> We should have at least one instance of Deserializing extant during all
> deserialization. It looks like one is missing from GetExternalDeclStmt.
>
> I think it's correct that ReadStmtFromStream does not try to maintain the
> stream position: it's intending to be called with the DeclsCursor pointing
> at the Stmt to read, and intends to leave the stream pointing to the record
> after that point. The external caller (GetExternalDeclStmt) jumps to the
> correct bit location (as do all other users of the DeclsCursor) before
> calling it, and does not expect to ever be called reentrantly. But a
> reentrant call to GetExternalDeclStmt is exactly what's happening in your
> case, because it also doesn't /defend/ against reentrancy from
> end-of-deserialization actions through a Deserializing object.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170224/a5dc7b38/attachment.html>
More information about the cfe-dev
mailing list