void IncrementalParser::SetTransformers(bool isChildInterpreter) { // Add transformers to the IncrementalParser, which owns them Sema* TheSema = &m_CI->getSema(); // Register the AST Transformers typedef std::unique_ptr<ASTTransformer> ASTTPtr_t; std::vector<ASTTPtr_t> ASTTransformers; ASTTransformers.emplace_back(new AutoSynthesizer(TheSema)); ASTTransformers.emplace_back(new EvaluateTSynthesizer(TheSema)); if (hasCodeGenerator() && !m_Interpreter->getOptions().NoRuntime) { // Don't protect against crashes if we cannot run anything. // cling might also be in a PCH-generation mode; don't inject our Sema pointer // into the PCH. ASTTransformers.emplace_back(new NullDerefProtectionTransformer(m_Interpreter)); } typedef std::unique_ptr<WrapperTransformer> WTPtr_t; std::vector<WTPtr_t> WrapperTransformers; if (!m_Interpreter->getOptions().NoRuntime) WrapperTransformers.emplace_back(new ValuePrinterSynthesizer(TheSema)); WrapperTransformers.emplace_back(new DeclExtractor(TheSema)); if (!m_Interpreter->getOptions().NoRuntime) WrapperTransformers.emplace_back(new ValueExtractionSynthesizer(TheSema, isChildInterpreter)); WrapperTransformers.emplace_back(new CheckEmptyTransactionTransformer(TheSema)); m_Consumer->SetTransformers(std::move(ASTTransformers), std::move(WrapperTransformers)); }
void IncrementalParser::codeGenTransaction(Transaction* T) { // codegen the transaction assert(T->getCompilationOpts().CodeGeneration && "CodeGen turned off"); assert(T->getState() == Transaction::kCompleted && "Must be completed"); assert(hasCodeGenerator() && "No CodeGen"); // Could trigger derserialization of decls. Transaction* deserT = beginTransaction(CompilationOptions()); // Commit this transaction first - T might need symbols from it, so // trigger emission of weak symbols by providing use. ParseResultTransaction PRT = endTransaction(deserT); commitTransaction(PRT); deserT = PRT.getPointer(); // This llvm::Module is done; finalize it and pass it to the execution // engine. if (!T->isNestedTransaction() && hasCodeGenerator()) { // The initializers are emitted to the symbol "_GLOBAL__sub_I_" + filename. // Make that unique! deserT = beginTransaction(CompilationOptions()); // Reset the module builder to clean up global initializers, c'tors, d'tors getCodeGenerator()->HandleTranslationUnit(getCI()->getASTContext()); auto PRT = endTransaction(deserT); commitTransaction(PRT); deserT = PRT.getPointer(); std::unique_ptr<llvm::Module> M(getCodeGenerator()->ReleaseModule()); if (M) { m_Interpreter->addModule(M.get(), T->getCompilationOpts().OptLevel); T->setModule(std::move(M)); } if (T->getIssuedDiags() != Transaction::kNone) { // Module has been released from Codegen, reset the Diags now. DiagnosticsEngine& Diags = getCI()->getSema().getDiagnostics(); Diags.Reset(/*soft=*/true); Diags.getClient()->clear(); } // Create a new module. StartModule(); } }
void IncrementalParser::Initialize() { if (hasCodeGenerator()) getCodeGenerator()->Initialize(getCI()->getASTContext()); CompilationOptions CO; CO.DeclarationExtraction = 0; CO.ValuePrinting = CompilationOptions::VPDisabled; CO.CodeGeneration = hasCodeGenerator(); // pull in PCHs const std::string& PCHFileName = m_CI->getInvocation ().getPreprocessorOpts().ImplicitPCHInclude; if (!PCHFileName.empty()) { Transaction* CurT = beginTransaction(CO); m_CI->createPCHExternalASTSource(PCHFileName, true /*DisablePCHValidation*/, true /*AllowPCHWithCompilerErrors*/, 0 /*DeserializationListener*/); Transaction* EndedT = endTransaction(CurT); commitTransaction(EndedT); } Transaction* CurT = beginTransaction(CO); Sema* TheSema = &m_CI->getSema(); m_Parser.reset(new Parser(m_CI->getPreprocessor(), *TheSema, false /*skipFuncBodies*/)); m_CI->getPreprocessor().EnterMainSourceFile(); // Initialize the parser after we have entered the main source file. m_Parser->Initialize(); // Perform initialization that occurs after the parser has been initialized // but before it parses anything. Initializes the consumers too. TheSema->Initialize(); ExternalASTSource *External = TheSema->getASTContext().getExternalSource(); if (External) External->StartTranslationUnit(m_Consumer); Transaction* EndedT = endTransaction(CurT); commitTransaction(EndedT); }
IncrementalParser::~IncrementalParser() { if (hasCodeGenerator()) { getCodeGenerator()->ReleaseModule(); } const Transaction* T = getFirstTransaction(); const Transaction* nextT = 0; while (T) { nextT = T->getNext(); delete T; T = nextT; } for (size_t i = 0; i < m_TTransformers.size(); ++i) delete m_TTransformers[i]; }
void IncrementalParser::codeGenTransaction(Transaction* T) { // codegen the transaction assert(T->getCompilationOpts().CodeGeneration && "CodeGen turned off"); assert(hasCodeGenerator() && "No CodeGen"); T->setModule(getCodeGenerator()->GetModule()); for (size_t Idx = 0; Idx < T->size() /*can change in the loop!*/; ++Idx) { // Copy DCI; it might get relocated below. Transaction::DelayCallInfo I = (*T)[Idx]; 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 // ASTConsumer::HandleInterestingDecl() getCodeGenerator()->HandleTopLevelDecl(I.m_DGR); } else if(I.m_Call == Transaction::kCCIHandleTagDeclDefinition) { TagDecl* TD = cast<TagDecl>(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleTagDeclDefinition(TD); } else if (I.m_Call == Transaction::kCCIHandleVTable) { CXXRecordDecl* CXXRD = cast<CXXRecordDecl>(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleVTable(CXXRD, /*isRequired*/true); } else if (I.m_Call == Transaction::kCCIHandleCXXImplicitFunctionInstantiation) { FunctionDecl* FD = cast<FunctionDecl>(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleCXXImplicitFunctionInstantiation(FD); } else if (I.m_Call == Transaction::kCCIHandleCXXStaticMemberVarInstantiation) { VarDecl* VD = cast<VarDecl>(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleCXXStaticMemberVarInstantiation(VD); } else if (I.m_Call == Transaction::kCCINone) ; // We use that internally as delimiter in the Transaction. else llvm_unreachable("We shouldn't have decl without call info."); } getCodeGenerator()->HandleTranslationUnit(getCI()->getASTContext()); }
IncrementalParser::~IncrementalParser() { if (hasCodeGenerator()) { getCodeGenerator()->ReleaseModule(); } const Transaction* T = getFirstTransaction(); const Transaction* nextT = 0; while (T) { assert((T->getState() == Transaction::kCommitted || T->getState() == Transaction::kRolledBack) && "Not committed?"); nextT = T->getNext(); delete T; T = nextT; } for (size_t i = 0; i < m_ASTTransformers.size(); ++i) delete m_ASTTransformers[i]; for (size_t i = 0; i < m_IRTransformers.size(); ++i) delete m_IRTransformers[i]; }
void IncrementalParser::commitTransaction(Transaction* T) { //Transaction* CurT = m_Consumer->getTransaction(); assert(T->isCompleted() && "Transaction not ended!?"); assert(T->getState() != Transaction::kCommitted && "Committing an already committed transaction."); // Check for errors... if (T->getIssuedDiags() == Transaction::kErrors) { rollbackTransaction(T); return; } if (T->hasNestedTransactions()) { for(Transaction::const_nested_iterator I = T->nested_begin(), E = T->nested_end(); I != E; ++I) if ((*I)->getState() != Transaction::kCommitted) commitTransaction(*I); } // We are sure it's safe to pipe it through the transformers bool success = true; for (size_t i = 0; i < m_TTransformers.size(); ++i) { success = m_TTransformers[i]->TransformTransaction(*T); if (!success) { break; } } m_CI->getDiagnostics().Reset(); // FIXME: Should be in rollback transaction. if (!success) { // Roll back on error in a transformer rollbackTransaction(T); return; } // Pull all template instantiations in that came from the consumers. getCI()->getSema().PerformPendingInstantiations(); m_Consumer->HandleTranslationUnit(getCI()->getASTContext()); if (T->getCompilationOpts().CodeGeneration && hasCodeGenerator()) { // codegen the transaction for (size_t Idx = 0; Idx < T->size() /*can change in the loop!*/; ++Idx) { // Copy DCI; it might get relocated below. Transaction::DelayCallInfo I = (*T)[Idx]; 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 // ASTConsumer::HandleInterestingDecl() getCodeGenerator()->HandleTopLevelDecl(I.m_DGR); } else if(I.m_Call == Transaction::kCCIHandleTagDeclDefinition) { TagDecl* TD = cast<TagDecl>(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleTagDeclDefinition(TD); } else if (I.m_Call == Transaction::kCCIHandleVTable) { CXXRecordDecl* CXXRD = cast<CXXRecordDecl>(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleVTable(CXXRD, /*isRequired*/true); } else if (I.m_Call == Transaction::kCCIHandleCXXImplicitFunctionInstantiation) { FunctionDecl* FD = cast<FunctionDecl>(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleCXXImplicitFunctionInstantiation(FD); } else if (I.m_Call == Transaction::kCCIHandleCXXStaticMemberVarInstantiation) { VarDecl* VD = cast<VarDecl>(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleCXXStaticMemberVarInstantiation(VD); } else if (I.m_Call == Transaction::kCCINone) ; // We use that internally as delimiter in the Transaction. else llvm_unreachable("We shouldn't have decl without call info."); } getCodeGenerator()->HandleTranslationUnit(getCI()->getASTContext()); T->setModule(getCodeGenerator()->GetModule()); // The static initializers might run anything and can thus cause more // decls that need to end up in a transaction. But this one is done // with CodeGen... T->setState(Transaction::kCommitting); // run the static initializers that came from codegenning if (m_Interpreter->runStaticInitializersOnce() >= Interpreter::kExeFirstError) { // Roll back on error in a transformer rollbackTransaction(T); return; } } else T->setState(Transaction::kCommitting); InterpreterCallbacks* callbacks = m_Interpreter->getCallbacks(); if (callbacks) { callbacks->TransactionCommitted(*T); } if (T->hasNestedTransactions()) { Transaction* SubTransactionWhileCommitting = *T->rnested_begin(); if (SubTransactionWhileCommitting->getState() == Transaction::kCollecting) { // A nested transaction was created while committing this // transaction; commit it now. SubTransactionWhileCommitting->setState(Transaction::kCompleted); commitTransaction(SubTransactionWhileCommitting); } } T->setState(Transaction::kCommitted); // If the transaction is empty do nothing. // Except it was nested transaction and we want to reuse it later on. if (T->empty() && T->isNestedTransaction()) { // We need to remove the marker from its parent. Transaction* ParentT = T->getParent(); for (size_t i = 0; i < ParentT->size(); ++i) if ((*ParentT)[i].m_DGR.isNull()) ParentT->erase(i); } if (T->isNestedTransaction()) { // TODO: Add proper logic in the case where there are multiple nested // transaction. This now won't handle the case where there are more than // one level 1 nested transactions. m_Consumer->setTransaction(T->getParent()); } }
void IncrementalParser::commitTransaction(Transaction* T) { //Transaction* CurT = m_Consumer->getTransaction(); assert(T->isCompleted() && "Transaction not ended!?"); assert(T->getState() != Transaction::kCommitted && "Committing an already committed transaction."); // If committing a nested transaction the active one should be its parent // from now on. if (T->isNestedTransaction()) m_Consumer->setTransaction(T->getParent()); // Check for errors... if (T->getIssuedDiags() == Transaction::kErrors) { rollbackTransaction(T); return; } if (T->hasNestedTransactions()) { for(Transaction::const_nested_iterator I = T->nested_begin(), E = T->nested_end(); I != E; ++I) if ((*I)->getState() != Transaction::kCommitted) commitTransaction(*I); } if (!transformTransactionAST(T)) return; // Here we expect a template instantiation. We need to open the transaction // that we are currently work with. Transaction::State oldState = T->getState(); T->setState(Transaction::kCollecting); // Pull all template instantiations in that came from the consumers. getCI()->getSema().PerformPendingInstantiations(); T->setState(oldState); m_Consumer->HandleTranslationUnit(getCI()->getASTContext()); if (T->getCompilationOpts().CodeGeneration && hasCodeGenerator()) { codeGenTransaction(T); transformTransactionIR(T); } // The static initializers might run anything and can thus cause more // decls that need to end up in a transaction. But this one is done // with CodeGen... T->setState(Transaction::kCommitted); if (T->getCompilationOpts().CodeGeneration && hasCodeGenerator()) { runStaticInitOnTransaction(T); } InterpreterCallbacks* callbacks = m_Interpreter->getCallbacks(); if (callbacks) callbacks->TransactionCommitted(*T); // If the transaction is empty do nothing. // Except it was nested transaction and we want to reuse it later on. if (T->empty() && T->isNestedTransaction()) { // We need to remove the marker from its parent. Transaction* ParentT = T->getParent(); for (size_t i = 0; i < ParentT->size(); ++i) if ((*ParentT)[i].m_DGR.isNull()) ParentT->erase(i); } }
void IncrementalParser::commitTransaction(ParseResultTransaction& PRT, bool ClearDiagClient) { Transaction* T = PRT.getPointer(); if (!T) { if (PRT.getInt() != kSuccess) { // Nothing has been emitted to Codegen, reset the Diags. DiagnosticsEngine& Diags = getCI()->getSema().getDiagnostics(); Diags.Reset(/*soft=*/true); if (ClearDiagClient) Diags.getClient()->clear(); } return; } assert(T->isCompleted() && "Transaction not ended!?"); assert(T->getState() != Transaction::kCommitted && "Committing an already committed transaction."); assert((T->getIssuedDiags() == Transaction::kErrors || !T->empty()) && "Valid Transactions must not be empty;"); // If committing a nested transaction the active one should be its parent // from now on. if (T->isNestedTransaction()) m_Consumer->setTransaction(T->getParent()); // Check for errors... if (T->getIssuedDiags() == Transaction::kErrors) { // Make module visible to TransactionUnloader. bool MustStartNewModule = false; if (!T->isNestedTransaction() && hasCodeGenerator()) { MustStartNewModule = true; std::unique_ptr<llvm::Module> M(getCodeGenerator()->ReleaseModule()); if (M) { T->setModule(std::move(M)); } } // Module has been released from Codegen, reset the Diags now. DiagnosticsEngine& Diags = getCI()->getSema().getDiagnostics(); Diags.Reset(/*soft=*/true); if (ClearDiagClient) Diags.getClient()->clear(); PRT.setPointer(nullptr); PRT.setInt(kFailed); m_Interpreter->unload(*T); // Create a new module if necessary. if (MustStartNewModule) StartModule(); return; } if (T->hasNestedTransactions()) { Transaction* TopmostParent = T->getTopmostParent(); EParseResult PR = kSuccess; if (TopmostParent->getIssuedDiags() == Transaction::kErrors) PR = kFailed; else if (TopmostParent->getIssuedDiags() == Transaction::kWarnings) PR = kSuccessWithWarnings; for (Transaction::const_nested_iterator I = T->nested_begin(), E = T->nested_end(); I != E; ++I) if ((*I)->getState() != Transaction::kCommitted) { ParseResultTransaction PRT(*I, PR); commitTransaction(PRT); } } // If there was an error coming from the transformers. if (T->getIssuedDiags() == Transaction::kErrors) { m_Interpreter->unload(*T); return; } // Here we expect a template instantiation. We need to open the transaction // that we are currently work with. { Transaction* prevConsumerT = m_Consumer->getTransaction(); m_Consumer->setTransaction(T); Transaction* nestedT = beginTransaction(T->getCompilationOpts()); // Pull all template instantiations in that came from the consumers. getCI()->getSema().PerformPendingInstantiations(); ParseResultTransaction nestedPRT = endTransaction(nestedT); commitTransaction(nestedPRT); m_Consumer->setTransaction(prevConsumerT); } m_Consumer->HandleTranslationUnit(getCI()->getASTContext()); // The static initializers might run anything and can thus cause more // decls that need to end up in a transaction. But this one is done // with CodeGen... if (T->getCompilationOpts().CodeGeneration && hasCodeGenerator()) { Transaction* prevConsumerT = m_Consumer->getTransaction(); m_Consumer->setTransaction(T); codeGenTransaction(T); T->setState(Transaction::kCommitted); if (!T->getParent()) { if (m_Interpreter->executeTransaction(*T) >= Interpreter::kExeFirstError) { // Roll back on error in initializers. // T maybe pointing to freed memory after this call: // Interpreter::unload // IncrementalParser::deregisterTransaction // TransactionPool::releaseTransaction m_Interpreter->unload(*T); return; } } m_Consumer->setTransaction(prevConsumerT); } T->setState(Transaction::kCommitted); if (InterpreterCallbacks* callbacks = m_Interpreter->getCallbacks()) callbacks->TransactionCommitted(*T); }
bool IncrementalParser::Initialize(llvm::SmallVectorImpl<ParseResultTransaction>& result, bool isChildInterpreter) { m_TransactionPool.reset(new TransactionPool); if (hasCodeGenerator()) getCodeGenerator()->Initialize(getCI()->getASTContext()); CompilationOptions CO = m_Interpreter->makeDefaultCompilationOpts(); Transaction* CurT = beginTransaction(CO); Preprocessor& PP = m_CI->getPreprocessor(); DiagnosticsEngine& Diags = m_CI->getSema().getDiagnostics(); // Pull in PCH. const std::string& PCHFileName = m_CI->getInvocation().getPreprocessorOpts().ImplicitPCHInclude; if (!PCHFileName.empty()) { Transaction* PchT = beginTransaction(CO); DiagnosticErrorTrap Trap(Diags); m_CI->createPCHExternalASTSource(PCHFileName, true /*DisablePCHValidation*/, true /*AllowPCHWithCompilerErrors*/, 0 /*DeserializationListener*/, true /*OwnsDeserializationListener*/); result.push_back(endTransaction(PchT)); if (Trap.hasErrorOccurred()) { result.push_back(endTransaction(CurT)); return false; } } addClingPragmas(*m_Interpreter); // Must happen after attaching the PCH, else PCH elements will end up // being lexed. PP.EnterMainSourceFile(); Sema* TheSema = &m_CI->getSema(); m_Parser.reset(new Parser(PP, *TheSema, false /*skipFuncBodies*/)); // Initialize the parser after PP has entered the main source file. m_Parser->Initialize(); ExternalASTSource *External = TheSema->getASTContext().getExternalSource(); if (External) External->StartTranslationUnit(m_Consumer); // Start parsing the "main file" to warm up lexing (enter caching lex mode // for ParseInternal()'s call EnterSourceFile() to make sense. while (!m_Parser->ParseTopLevelDecl()) {} // If I belong to the parent Interpreter, am using C++, and -noruntime // wasn't given on command line, then #include <new> and check ABI if (!isChildInterpreter && m_CI->getLangOpts().CPlusPlus && !m_Interpreter->getOptions().NoRuntime) { // <new> is needed by the ValuePrinter so it's a good thing to include it. // We need to include it to determine the version number of the standard // library implementation. ParseInternal("#include <new>"); // That's really C++ ABI compatibility. C has other problems ;-) CheckABICompatibility(*m_Interpreter); } // DO NOT commit the transactions here: static initialization in these // transactions requires gCling through local_cxa_atexit(), but that has not // been defined yet! ParseResultTransaction PRT = endTransaction(CurT); result.push_back(PRT); return true; }