Move codegenning of deserialized declarations in the IncrementalParser.

We had two different codepath for codegeneration. The first one was for
declarations that came from text and the second one for declarations that came
from 'ExternalSource' such as PCH. In the latter case we had to do some
extra equilibristics to emulate a PCM and ignore generating code for decls with
static storage, because it will clash with the loading of the library that already
contains them.

The advantage of the new implementation is that instead of communicating the
deserialized decls to ROOT via some fishy deserialization listeners we can use
the cling::Transaction as we use it for decls that came from code.
This commit is contained in:
Vassil Vassilev 2013-08-26 17:59:33 +02:00 committed by sftnight
parent 2e97001848
commit 59ced3f193
4 changed files with 65 additions and 123 deletions

View File

@ -30,98 +30,27 @@ namespace cling {
return D->isFromASTFile();
}
bool DeclCollector::shouldIgnoreDeclFromASTReader(const Decl* D) const {
// Functions that are inlined must be sent to CodeGen - they will not have a
// symbol in the library.
if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
if (D->isFromASTFile())
return !FD->hasBody();
else
return !FD->isInlined();
}
// Don't codegen statics coming in from a module; they are already part of
// the library.
if (const VarDecl* VD = dyn_cast<VarDecl>(D))
if (VD->hasGlobalStorage())
return true;
return false;
}
// pin the vtable here.
DeclCollector::~DeclCollector() {
}
bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) {
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
// pipe it directly to codegen.
if (comesFromASTReader(DGR)) {
if (m_CodeGen) {
for (DeclGroupRef::iterator I = DGR.begin(), E = DGR.end();
I != E; ++I) {
if (NamespaceDecl* ND = dyn_cast<NamespaceDecl>(*I)) {
for (NamespaceDecl::decl_iterator IN = ND->decls_begin(),
EN = ND->decls_end(); IN != EN; ++IN)
// Recurse over decls inside the namespace, like
// CodeGenModule::EmitNamespace() does.
HandleTopLevelDecl(DeclGroupRef(*IN));
} else {
if (!shouldIgnoreDeclFromASTReader(*I)) {
m_CodeGen->HandleTopLevelDecl(DeclGroupRef(*I));
}
// FIXME: once modules are there this is not needed anymore.
// it is used to simulate modules and the ASTDeserializationListener
// for sources that are included to describe the library that was
// built from the sources (ACLiC).
if (!(*I)->isFromASTFile() && m_Interp->getASTDeserializationListener())
m_Interp->getASTDeserializationListener()->DeclRead(0, *I);
}
}
}
//return true;
}
DeclCollector::~DeclCollector() { }
bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) {
Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleTopLevelDecl);
m_CurTransaction->append(DCI);
return true;
}
void DeclCollector::HandleInterestingDecl(DeclGroupRef DGR) {
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
// pipe it directly to codegen.
if (comesFromASTReader(DGR)) {
HandleTopLevelDecl(DGR);
//return;
}
Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleInterestingDecl);
m_CurTransaction->append(DCI);
}
void DeclCollector::HandleTagDeclDefinition(TagDecl* TD) {
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
// pipe it directly to codegen.
if (comesFromASTReader(DeclGroupRef(TD))) {
if (m_CodeGen)
m_CodeGen->HandleTagDeclDefinition(TD);
//return;
}
Transaction::DelayCallInfo DCI(DeclGroupRef(TD),
Transaction::kCCIHandleTagDeclDefinition);
m_CurTransaction->append(DCI);
}
void DeclCollector::HandleVTable(CXXRecordDecl* RD, bool DefinitionRequired) {
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
// pipe it directly to codegen.
if (comesFromASTReader(DeclGroupRef(RD))) {
// FIXME: when is the vtable part of the library?
if (m_CodeGen)
m_CodeGen->HandleVTable(RD, DefinitionRequired);
//return;
}
Transaction::DelayCallInfo DCI(DeclGroupRef(RD),
Transaction::kCCIHandleVTable);
m_CurTransaction->append(DCI);
@ -142,27 +71,11 @@ namespace cling {
}
void DeclCollector::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
// pipe it directly to codegen.
if (comesFromASTReader(DeclGroupRef(D))) {
if (m_CodeGen)
m_CodeGen->HandleCXXImplicitFunctionInstantiation(D);
//return;
}
Transaction::DelayCallInfo DCI(DeclGroupRef(D),
Transaction::kCCIHandleCXXImplicitFunctionInstantiation);
m_CurTransaction->append(DCI);
}
void DeclCollector::HandleCXXStaticMemberVarInstantiation(VarDecl *D) {
// if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed
// pipe it directly to codegen.
if (comesFromASTReader(DeclGroupRef(D))) {
if (m_CodeGen && !shouldIgnoreDeclFromASTReader(D))
m_CodeGen->HandleCXXStaticMemberVarInstantiation(D);
//return;
}
Transaction::DelayCallInfo DCI(DeclGroupRef(D),
Transaction::kCCIHandleCXXStaticMemberVarInstantiation);
m_CurTransaction->append(DCI);

View File

@ -31,36 +31,15 @@ namespace cling {
private:
Transaction* m_CurTransaction;
///\brief This is the fast path for the declarations which do not need
/// special handling. Eg. deserialized declarations.
clang::CodeGenerator* m_CodeGen; // we do not own.
///\brief Interpreter feeding into the DeclCollector. Only used for
/// a temporary workaround until modules work.
/// FIXME: remove once modules work.
cling::Interpreter* m_Interp; // we do not own.
///\brief Test whether the first decl of the DeclGroupRef comes from an AST
/// file.
///
bool comesFromASTReader(clang::DeclGroupRef DGR) const;
/// \brief Return true if this decl (which comes from an AST file) should
// not be sent to CodeGen. The module is assumed to describe the contents of
// a library; symbols inside the library must thus not be reemitted /
// duplicated by CodeGen.
bool shouldIgnoreDeclFromASTReader(const clang::Decl* D) const;
public:
DeclCollector() :
m_CurTransaction(0), m_CodeGen(0), m_Interp(0) {}
DeclCollector() : m_CurTransaction(0){}
virtual ~DeclCollector();
// FIXME: Gross hack, which should disappear when we move some of the
// initialization happening in the IncrementalParser to the CIFactory.
void setCodeGen(clang::CodeGenerator* codeGen) { m_CodeGen = codeGen; }
// FIXME: Gross hack, which should disappear when m_Interp can go.
void setInterpreter(cling::Interpreter* Interp) { m_Interp = Interp; }
/// \{
/// \name ASTConsumer overrides

View File

@ -56,7 +56,6 @@ namespace cling {
m_Consumer = dyn_cast<DeclCollector>(&CI->getASTConsumer());
assert(m_Consumer && "Expected ChainedConsumer!");
m_Consumer->setInterpreter(interp);
m_CI.reset(CI);
@ -66,7 +65,6 @@ namespace cling {
CI->getTargetOpts(),
*m_Interpreter->getLLVMContext()
));
m_Consumer->setCodeGen(m_CodeGen.get());
}
initializeVirtualFile();
@ -352,19 +350,43 @@ namespace cling {
llvm_unreachable("We shouldn't have decl without call info.");
}
// Treat the deserialized decls differently.
const CompilationOptions& CO(T->getCompilationOpts());
for (Transaction::iterator I = T->deserialized_decls_begin(),
E = T->deserialized_decls_end(); I != E; ++I) {
// Skip unless we find at least one used decl.
bool skip = true;
for (DeclGroupRef::const_iterator J = I->m_DGR.begin(),
JE = I->m_DGR.end(); J != JE; ++J) {
if ((*J)->hasAttr<UsedAttr>())
skip = false;
if (I->m_Call == Transaction::kCCIHandleTopLevelDecl) {
// FIXME: This flag means that we should skip the namespace codegen,
// because we did it already. This works around issue with the static
// initialization when having a PCH and loading a library. We don't want
// to generate code for the static that will come through the library.
//
// This will be fixed with the clang::Modules. Make sure we remember.
assert(!getCI()->getLangOpts().Modules && "Please revisit!");
bool shouldContinue = false;
for (DeclGroupRef::iterator DI = I->m_DGR.begin(), DE = I->m_DGR.end();
DI != DE; ++DI)
if (NamespaceDecl* ND = dyn_cast<NamespaceDecl>(*DI)) {
shouldContinue = true;
for (NamespaceDecl::decl_iterator IN = ND->decls_begin(),
EN = ND->decls_end(); IN != EN; ++IN) {
// Recurse over decls inside the namespace, like
// CodeGenModule::EmitNamespace() does.
DeclGroupRef INDGR = DeclGroupRef(*IN);
if (!shouldIgnore(INDGR))
getCodeGenerator()->HandleTopLevelDecl(INDGR);
}
}
if (shouldContinue)
continue;
}
if (skip)
if (shouldIgnore(I->m_DGR))
continue;
if (I->m_Call == Transaction::kCCIHandleTopLevelDecl)
if (I->m_Call == Transaction::kCCIHandleTopLevelDecl) {
getCodeGenerator()->HandleTopLevelDecl(I->m_DGR);
}
else if (I->m_Call == Transaction::kCCIHandleInterestingDecl) {
// Usually through BackendConsumer which doesn't implement
// HandleInterestingDecl() and thus calls
@ -611,4 +633,25 @@ namespace cling {
}
}
bool IncrementalParser::shouldIgnore(DeclGroupRef DGR) const {
// Take the first/only decl in the group. The second must have the same
// properties as the first Decl in the group.
const Decl* D = *DGR.begin();
// Functions that are inlined must be sent to CodeGen - they will not have a
// symbol in the library.
if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
if (D->isFromASTFile())
return !FD->hasBody();
else
return !FD->isInlined();
}
// Don't codegen statics coming in from a module; they are already part of
// the library.
if (const VarDecl* VD = dyn_cast<VarDecl>(D))
if (VD->hasGlobalStorage())
return true;
return false;
}
} // namespace cling

View File

@ -24,11 +24,11 @@ namespace llvm {
namespace clang {
class CodeGenerator;
class CompilerInstance;
class DeclGroupRef;
class FileID;
class Parser;
}
namespace cling {
class CompilationOptions;
class CIFactory;
@ -229,6 +229,13 @@ namespace cling {
///\param[in] input - The incremental input that needs to be parsed.
///
EParseResult ParseInternal(llvm::StringRef input);
///\brief Return true if this decl (which comes from an AST file) should
/// not be sent to CodeGen. The module is assumed to describe the contents
/// of a library; symbols inside the library must thus not be reemitted /
/// duplicated by CodeGen.
///
bool shouldIgnore(clang::DeclGroupRef DGR) const;
};
} // end namespace cling
#endif // CLING_INCREMENTAL_PARSER_H