Author: spyffe Date: Tue Mar 22 16:05:51 2016 New Revision: 264095 URL: http://llvm.org/viewvc/llvm-project?rev=264095&view=rev Log: Backend support for top-level Clang epxressions
This patch adds a new ExecutionPolicy, eExecutionPolicyTopLevel, which tells the expression parser that the expression should be JITted as top level code but nothing (except static initializers) should be run. I have modified the Clang expression parser to recognize this execution policy. On top of the existing patches that support storing IR and maintaining a map of arbitrary Decls, this is mainly just patching up a few places in the expression parser. I intend to submit a patch for review that exposes this functionality through the "expression" command and through the SB API. That patch also includes a testcase for all of this. <rdar://problem/22864976> Modified: lldb/trunk/include/lldb/lldb-private-enumerations.h lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h Modified: lldb/trunk/include/lldb/lldb-private-enumerations.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-enumerations.h?rev=264095&r1=264094&r2=264095&view=diff ============================================================================== --- lldb/trunk/include/lldb/lldb-private-enumerations.h (original) +++ lldb/trunk/include/lldb/lldb-private-enumerations.h Tue Mar 22 16:05:51 2016 @@ -164,11 +164,12 @@ typedef enum FormatCategoryItem //------------------------------------------------------------------ /// Expression execution policies -//------------------------------------------------------------------ +//------------------------------------------------------------------ typedef enum { eExecutionPolicyOnlyWhenNeeded, eExecutionPolicyNever, - eExecutionPolicyAlways + eExecutionPolicyAlways, + eExecutionPolicyTopLevel // used for top-level code } ExecutionPolicy; //---------------------------------------------------------------------- Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp?rev=264095&r1=264094&r2=264095&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp (original) +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp Tue Mar 22 16:05:51 2016 @@ -11,6 +11,11 @@ #include "ClangPersistentVariables.h" +#include "lldb/Core/Log.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangASTImporter.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBAssert.h" #include "stdlib.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -23,22 +28,18 @@ #include "clang/Sema/SemaDiagnostic.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" -#include "lldb/Core/Log.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Target/Target.h" using namespace llvm; using namespace clang; using namespace lldb_private; -ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough, - Target &target) : - m_ast_context (NULL), - m_passthrough (passthrough), - m_passthrough_sema (NULL), - m_target (target), - m_sema (NULL) +ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough, bool top_level, Target &target) + : m_ast_context(NULL), + m_passthrough(passthrough), + m_passthrough_sema(NULL), + m_target(target), + m_sema(NULL), + m_top_level(top_level) { if (!m_passthrough) return; @@ -76,6 +77,10 @@ ASTResultSynthesizer::TransformTopLevelD log->Printf("TransformTopLevelDecl(<complex>)"); } + if (m_top_level) + { + RecordPersistentDecl(named_decl); + } } if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D)) @@ -89,22 +94,23 @@ ASTResultSynthesizer::TransformTopLevelD TransformTopLevelDecl(*decl_iterator); } } - else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D)) + else if (!m_top_level) { - if (m_ast_context && - !method_decl->getSelector().getAsString().compare("$__lldb_expr:")) + if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D)) { - RecordPersistentTypes(method_decl); - SynthesizeObjCMethodResult(method_decl); + if (m_ast_context && !method_decl->getSelector().getAsString().compare("$__lldb_expr:")) + { + RecordPersistentTypes(method_decl); + SynthesizeObjCMethodResult(method_decl); + } } - } - else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D)) - { - if (m_ast_context && - !function_decl->getNameInfo().getAsString().compare("$__lldb_expr")) + else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D)) { - RecordPersistentTypes(function_decl); - SynthesizeFunctionResult(function_decl); + if (m_ast_context && !function_decl->getNameInfo().getAsString().compare("$__lldb_expr")) + { + RecordPersistentTypes(function_decl); + SynthesizeFunctionResult(function_decl); + } } } } @@ -457,14 +463,66 @@ ASTResultSynthesizer::MaybeRecordPersist ConstString name_cs(name.str().c_str()); if (log) - log->Printf ("Recording persistent type %s\n", name_cs.GetCString()); + log->Printf("Recording persistent type %s\n", name_cs.GetCString()); + + m_decls.push_back(D); +} + +void +ASTResultSynthesizer::RecordPersistentDecl(NamedDecl *D) +{ + lldbassert(m_top_level); + + if (!D->getIdentifier()) + return; + + StringRef name = D->getName(); + + if (name.size() == 0) + return; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + ConstString name_cs(name.str().c_str()); + + if (log) + log->Printf("Recording persistent decl %s\n", name_cs.GetCString()); - Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl(m_target.GetScratchClangASTContext()->getASTContext(), - m_ast_context, - D); + m_decls.push_back(D); +} - if (TypeDecl *TypeDecl_scratch = dyn_cast<TypeDecl>(D_scratch)) - llvm::cast<ClangPersistentVariables>(m_target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC))->RegisterPersistentDecl(name_cs, TypeDecl_scratch); +void +ASTResultSynthesizer::CommitPersistentDecls() +{ + for (clang::NamedDecl *decl : m_decls) + { + StringRef name = decl->getName(); + ConstString name_cs(name.str().c_str()); + + Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl( + m_target.GetScratchClangASTContext()->getASTContext(), m_ast_context, decl); + + if (!D_scratch) + { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + { + std::string s; + llvm::raw_string_ostream ss(s); + decl->dump(ss); + ss.flush(); + + log->Printf("Couldn't commit persistent decl: %s\n", s.c_str()); + } + + continue; + } + + if (NamedDecl *NamedDecl_scratch = dyn_cast<NamedDecl>(D_scratch)) + llvm::cast<ClangPersistentVariables>(m_target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)) + ->RegisterPersistentDecl(name_cs, NamedDecl_scratch); + } } void Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h?rev=264095&r1=264094&r2=264095&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h (original) +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h Tue Mar 22 16:05:51 2016 @@ -41,13 +41,16 @@ public: /// pass to the next step in the chain after processing. Passthrough is /// the next ASTConsumer, or NULL if none is required. /// + /// @param[in] top_level + /// If true, register all top-level Decls and don't try to handle the + /// main function. + /// /// @param[in] target /// The target, which contains the persistent variable store and the /// AST importer. //---------------------------------------------------------------------- - ASTResultSynthesizer(clang::ASTConsumer *passthrough, - Target &target); - + ASTResultSynthesizer(clang::ASTConsumer *passthrough, bool top_level, Target &target); + //---------------------------------------------------------------------- /// Destructor //---------------------------------------------------------------------- @@ -106,11 +109,18 @@ public: /// casts it to an Action for actual use. //---------------------------------------------------------------------- void InitializeSema(clang::Sema &S) override; - + //---------------------------------------------------------------------- /// Reset the Sema to NULL now that transformations are done //---------------------------------------------------------------------- - void ForgetSema() override; + void + ForgetSema() override; + + //---------------------------------------------------------------------- + /// The parse has succeeded, so record its persistent decls + //---------------------------------------------------------------------- + void + CommitPersistentDecls(); private: //---------------------------------------------------------------------- @@ -171,13 +181,30 @@ private: /// @param[in] Body /// The body of the function. //---------------------------------------------------------------------- - void MaybeRecordPersistentType(clang::TypeDecl *D); - - clang::ASTContext *m_ast_context; ///< The AST context to use for identifiers and types. - clang::ASTConsumer *m_passthrough; ///< The ASTConsumer down the chain, for passthrough. NULL if it's a SemaConsumer. - clang::SemaConsumer *m_passthrough_sema; ///< The SemaConsumer down the chain, for passthrough. NULL if it's an ASTConsumer. - Target &m_target; ///< The target, which contains the persistent variable store and the - clang::Sema *m_sema; ///< The Sema to use. + void + MaybeRecordPersistentType(clang::TypeDecl *D); + + //---------------------------------------------------------------------- + /// Given a NamedDecl, register it as a pointer type in the target's scratch + /// AST context. + /// + /// @param[in] Body + /// The body of the function. + //---------------------------------------------------------------------- + void + RecordPersistentDecl(clang::NamedDecl *D); + + clang::ASTContext *m_ast_context; ///< The AST context to use for identifiers and types. + clang::ASTConsumer + *m_passthrough; ///< The ASTConsumer down the chain, for passthrough. NULL if it's a SemaConsumer. + clang::SemaConsumer + *m_passthrough_sema; ///< The SemaConsumer down the chain, for passthrough. NULL if it's an ASTConsumer. + + std::vector<clang::NamedDecl *> m_decls; ///< Persistent declarations to register assuming the expression succeeds. + + Target &m_target; ///< The target, which contains the persistent variable store and the + clang::Sema *m_sema; ///< The Sema to use. + bool m_top_level; }; } // namespace lldb_private Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h?rev=264095&r1=264094&r2=264095&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h (original) +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h Tue Mar 22 16:05:51 2016 @@ -67,11 +67,14 @@ public: /// the ASTs to after transformation. //------------------------------------------------------------------ virtual clang::ASTConsumer * - ASTTransformer (clang::ASTConsumer *passthrough) = 0; - + ASTTransformer(clang::ASTConsumer *passthrough) = 0; -protected: + virtual void + CommitPersistentDecls() + { + } +protected: }; } // namespace lldb_private Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp?rev=264095&r1=264094&r2=264095&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (original) +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp Tue Mar 22 16:05:51 2016 @@ -652,6 +652,11 @@ ClangExpressionParser::Parse(DiagnosticM } } + if (!num_errors) + { + type_system_helper->CommitPersistentDecls(); + } + adapter->ResetManager(); return num_errors; @@ -697,24 +702,27 @@ ClangExpressionParser::PrepareForExecuti return err; } - // Find the actual name of the function (it's often mangled somehow) - ConstString function_name; - if (!FindFunctionInModule(function_name, llvm_module_ap.get(), m_expr.FunctionName())) - { - err.SetErrorToGenericError(); - err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName()); - return err; - } - else + if (execution_policy != eExecutionPolicyTopLevel) { - if (log) - log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName()); + // Find the actual name of the function (it's often mangled somehow) + + if (!FindFunctionInModule(function_name, llvm_module_ap.get(), m_expr.FunctionName())) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName()); + return err; + } + else + { + if (log) + log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName()); + } } - + SymbolContext sc; - + if (lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP()) { sc = frame_sp->GetSymbolContext(lldb::eSymbolContextEverything); @@ -741,20 +749,28 @@ ClangExpressionParser::PrepareForExecuti if (target) error_stream = target->GetDebugger().GetErrorFile().get(); - IRForTarget ir_for_target(decl_map, - m_expr.NeedsVariableResolution(), - *execution_unit_sp, - error_stream, + IRForTarget ir_for_target(decl_map, m_expr.NeedsVariableResolution(), *execution_unit_sp, error_stream, function_name.AsCString()); bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule()); - Error interpret_error; Process *process = exe_ctx.GetProcessPtr(); - bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls(); - can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error, interpret_function_calls); + if (execution_policy != eExecutionPolicyAlways && execution_policy != eExecutionPolicyTopLevel) + { + Error interpret_error; + + bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls(); + can_interpret = + IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), + interpret_error, interpret_function_calls); + if (!can_interpret && execution_policy == eExecutionPolicyNever) + { + err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString()); + return err; + } + } if (!ir_can_run) { @@ -762,19 +778,21 @@ ClangExpressionParser::PrepareForExecuti return err; } - if (!can_interpret && execution_policy == eExecutionPolicyNever) + if (!process && execution_policy == eExecutionPolicyAlways) { - err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString()); + err.SetErrorString("Expression needed to run in the target, but the target can't be run"); return err; } - if (!process && execution_policy == eExecutionPolicyAlways) + if (!process && execution_policy == eExecutionPolicyTopLevel) { - err.SetErrorString("Expression needed to run in the target, but the target can't be run"); + err.SetErrorString( + "Top-level code needs to be inserted into a runnable target, but the target can't be run"); return err; } - if (execution_policy == eExecutionPolicyAlways || !can_interpret) + if (execution_policy == eExecutionPolicyAlways || + (execution_policy != eExecutionPolicyTopLevel && !can_interpret)) { if (m_expr.NeedsValidation() && process) { @@ -809,7 +827,11 @@ ClangExpressionParser::PrepareForExecuti return err; } } + } + if (execution_policy == eExecutionPolicyAlways || execution_policy == eExecutionPolicyTopLevel || + !can_interpret) + { execution_unit_sp->GetRunnableInfo(err, func_addr, func_end); } } Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp?rev=264095&r1=264094&r2=264095&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp (original) +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp Tue Mar 22 16:05:51 2016 @@ -55,28 +55,25 @@ using namespace lldb_private; -ClangUserExpression::ClangUserExpression (ExecutionContextScope &exe_scope, - const char *expr, - const char *expr_prefix, - lldb::LanguageType language, - ResultType desired_type, - const EvaluateExpressionOptions &options) : - LLVMUserExpression (exe_scope, expr, expr_prefix, language, desired_type, options), - m_type_system_helper(*m_target_wp.lock().get()) +ClangUserExpression::ClangUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix, + lldb::LanguageType language, ResultType desired_type, + const EvaluateExpressionOptions &options) + : LLVMUserExpression(exe_scope, expr, expr_prefix, language, desired_type, options), + m_type_system_helper(*m_target_wp.lock().get(), options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { switch (m_language) { - case lldb::eLanguageTypeC_plus_plus: - m_allow_cxx = true; - break; - case lldb::eLanguageTypeObjC: - m_allow_objc = true; - break; - case lldb::eLanguageTypeObjC_plus_plus: - default: - m_allow_cxx = true; - m_allow_objc = true; - break; + case lldb::eLanguageTypeC_plus_plus: + m_allow_cxx = true; + break; + case lldb::eLanguageTypeObjC: + m_allow_objc = true; + break; + case lldb::eLanguageTypeObjC_plus_plus: + default: + m_allow_cxx = true; + m_allow_objc = true; + break; } } @@ -402,22 +399,30 @@ ClangUserExpression::Parse(DiagnosticMan } } } - - std::unique_ptr<ExpressionSourceCode> source_code (ExpressionSourceCode::CreateWrapped(prefix.c_str(), m_expr_text.c_str())); - - lldb::LanguageType lang_type; - if (m_in_cplusplus_method) - lang_type = lldb::eLanguageTypeC_plus_plus; - else if (m_in_objectivec_method) - lang_type = lldb::eLanguageTypeObjC; + if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) + { + m_transformed_text = m_expr_text; + } else - lang_type = lldb::eLanguageTypeC; - - if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_in_static_method, exe_ctx)) { - diagnostic_manager.PutCString(eDiagnosticSeverityError, "couldn't construct expression body"); - return false; + std::unique_ptr<ExpressionSourceCode> source_code( + ExpressionSourceCode::CreateWrapped(prefix.c_str(), m_expr_text.c_str())); + + lldb::LanguageType lang_type; + + if (m_in_cplusplus_method) + lang_type = lldb::eLanguageTypeC_plus_plus; + else if (m_in_objectivec_method) + lang_type = lldb::eLanguageTypeObjC; + else + lang_type = lldb::eLanguageTypeC; + + if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_in_static_method, exe_ctx)) + { + diagnostic_manager.PutCString(eDiagnosticSeverityError, "couldn't construct expression body"); + return false; + } } if (log) @@ -473,6 +478,11 @@ ClangUserExpression::Parse(DiagnosticMan return false; } + if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) + { + DeclMap()->SetLookupsEnabled(true); + } + Process *process = exe_ctx.GetProcessPtr(); ExecutionContextScope *exe_scope = process; @@ -497,16 +507,60 @@ ClangUserExpression::Parse(DiagnosticMan // Prepare the output of the parser for execution, evaluating it statically if possible // - Error jit_error = parser.PrepareForExecution (m_jit_start_addr, - m_jit_end_addr, - m_execution_unit_sp, - exe_ctx, - m_can_interpret, - execution_policy); + { + Error jit_error = parser.PrepareForExecution(m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx, + m_can_interpret, execution_policy); + + if (!jit_error.Success()) + { + const char *error_cstr = jit_error.AsCString(); + if (error_cstr && error_cstr[0]) + diagnostic_manager.PutCString(eDiagnosticSeverityError, error_cstr); + else + diagnostic_manager.PutCString(eDiagnosticSeverityError, "expression can't be interpreted or run"); + return false; + } + } + + if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) + { + Error static_init_error = parser.RunStaticInitializers(m_execution_unit_sp, exe_ctx); + + if (!static_init_error.Success()) + { + const char *error_cstr = static_init_error.AsCString(); + if (error_cstr && error_cstr[0]) + diagnostic_manager.Printf(eDiagnosticSeverityError, "couldn't run static initializers: %s\n", + error_cstr); + else + diagnostic_manager.PutCString(eDiagnosticSeverityError, "couldn't run static initializers\n"); + return false; + } + } + + if (m_execution_unit_sp) + { + bool register_execution_unit = false; + + if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) + { + register_execution_unit = true; + } + + if (register_execution_unit) + { + // We currently key off there being more than one external function in the execution + // unit to determine whether it needs to live in the process. + + llvm::cast<PersistentExpressionState>( + exe_ctx.GetTargetPtr()->GetPersistentExpressionStateForLanguage(m_language)) + ->RegisterExecutionUnit(m_execution_unit_sp); + } + } if (generate_debug_info) { - lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule()); + lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule()); if (jit_module_sp) { @@ -517,41 +571,14 @@ ClangUserExpression::Parse(DiagnosticMan m_jit_module_wp = jit_module_sp; target->GetImages().Append(jit_module_sp); } -// lldb_private::ObjectFile *jit_obj_file = jit_module_sp->GetObjectFile(); -// StreamFile strm (stdout, false); -// if (jit_obj_file) -// { -// jit_obj_file->GetSectionList(); -// jit_obj_file->GetSymtab(); -// jit_obj_file->Dump(&strm); -// } -// lldb_private::SymbolVendor *jit_sym_vendor = jit_module_sp->GetSymbolVendor(); -// if (jit_sym_vendor) -// { -// lldb_private::SymbolContextList sc_list; -// jit_sym_vendor->FindFunctions(const_func_name, NULL, lldb::eFunctionNameTypeFull, true, false, sc_list); -// sc_list.Dump(&strm, target); -// jit_sym_vendor->Dump(&strm); -// } - } - - ResetDeclMap(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions. - - if (jit_error.Success()) - { - if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS) - m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); - return true; - } - else - { - const char *error_cstr = jit_error.AsCString(); - if (error_cstr && error_cstr[0]) - diagnostic_manager.PutCString(eDiagnosticSeverityError, error_cstr); - else - diagnostic_manager.Printf(eDiagnosticSeverityError, "expression can't be interpreted or run"); - return false; } + + ResetDeclMap(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any + // ClangASTImporter::Minions. + + if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS) + m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); + return true; } bool @@ -637,14 +664,22 @@ ClangUserExpression::ClangUserExpression } clang::ASTConsumer * -ClangUserExpression::ClangUserExpressionHelper::ASTTransformer (clang::ASTConsumer *passthrough) +ClangUserExpression::ClangUserExpressionHelper::ASTTransformer(clang::ASTConsumer *passthrough) { - m_result_synthesizer_up.reset(new ASTResultSynthesizer(passthrough, - m_target)); + m_result_synthesizer_up.reset(new ASTResultSynthesizer(passthrough, m_top_level, m_target)); return m_result_synthesizer_up.get(); } +void +ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() +{ + if (m_result_synthesizer_up.get()) + { + m_result_synthesizer_up->CommitPersistentDecls(); + } +} + ClangUserExpression::ResultDelegate::ResultDelegate() { } Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h?rev=264095&r1=264094&r2=264095&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h (original) +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h Tue Mar 22 16:05:51 2016 @@ -51,13 +51,10 @@ public: class ClangUserExpressionHelper : public ClangExpressionHelper { public: - ClangUserExpressionHelper (Target &target) : - m_target(target) - { - } - + ClangUserExpressionHelper(Target &target, bool top_level) : m_target(target), m_top_level(top_level) {} + ~ClangUserExpressionHelper() override = default; - + //------------------------------------------------------------------ /// Return the object that the parser should use when resolving external /// values. May be NULL if everything should be self-contained. @@ -88,11 +85,16 @@ public: clang::ASTConsumer * ASTTransformer(clang::ASTConsumer *passthrough) override; + void + CommitPersistentDecls() override; + private: - Target &m_target; + Target &m_target; std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up; - std::unique_ptr<ASTStructExtractor> m_struct_extractor_up; ///< The class that generates the argument struct layout. + std::unique_ptr<ASTStructExtractor> + m_struct_extractor_up; ///< The class that generates the argument struct layout. std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer_up; + bool m_top_level; }; //------------------------------------------------------------------ Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp?rev=264095&r1=264094&r2=264095&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp (original) +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp Tue Mar 22 16:05:51 2016 @@ -1957,25 +1957,29 @@ IRForTarget::runOnModule (Module &llvm_m log->Printf("Module as passed in to IRForTarget: \n\"%s\"", s.c_str()); } - Function* main_function = m_module->getFunction(StringRef(m_func_name.c_str())); + Function *const main_function = m_func_name.IsEmpty() ? nullptr : m_module->getFunction(m_func_name.GetStringRef()); - if (!main_function) + if (!m_func_name.IsEmpty() && !main_function) { if (log) - log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str()); + log->Printf("Couldn't find \"%s()\" in the module", m_func_name.AsCString()); if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", m_func_name.c_str()); + m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", + m_func_name.AsCString()); return false; } - if (!FixFunctionLinkage (*main_function)) + if (main_function) { - if (log) - log->Printf("Couldn't fix the linkage for the function"); + if (!FixFunctionLinkage(*main_function)) + { + if (log) + log->Printf("Couldn't fix the linkage for the function"); - return false; + return false; + } } llvm::Type *int8_ty = Type::getInt8Ty(m_module->getContext()); @@ -1994,14 +1998,17 @@ IRForTarget::runOnModule (Module &llvm_m // Replace $__lldb_expr_result with a persistent variable // - if (!CreateResultVariable(*main_function)) + if (main_function) { - if (log) - log->Printf("CreateResultVariable() failed"); + if (!CreateResultVariable(*main_function)) + { + if (log) + log->Printf("CreateResultVariable() failed"); - // CreateResultVariable() reports its own errors, so we don't do so here + // CreateResultVariable() reports its own errors, so we don't do so here - return false; + return false; + } } if (log && log->GetVerbose()) @@ -2125,24 +2132,27 @@ IRForTarget::runOnModule (Module &llvm_m // Run function-level passes that only make sense on the main function // - if (!ResolveExternals(*main_function)) + if (main_function) { - if (log) - log->Printf("ResolveExternals() failed"); + if (!ResolveExternals(*main_function)) + { + if (log) + log->Printf("ResolveExternals() failed"); - // ResolveExternals() reports its own errors, so we don't do so here + // ResolveExternals() reports its own errors, so we don't do so here - return false; - } + return false; + } - if (!ReplaceVariables(*main_function)) - { - if (log) - log->Printf("ReplaceVariables() failed"); + if (!ReplaceVariables(*main_function)) + { + if (log) + log->Printf("ReplaceVariables() failed"); - // ReplaceVariables() reports its own errors, so we don't do so here + // ReplaceVariables() reports its own errors, so we don't do so here - return false; + return false; + } } if (log && log->GetVerbose()) Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h?rev=264095&r1=264094&r2=264095&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h (original) +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/IRForTarget.h Tue Mar 22 16:05:51 2016 @@ -546,40 +546,45 @@ private: /// @return /// True on success; false otherwise //------------------------------------------------------------------ - bool - ReplaceVariables (llvm::Function &llvm_function); - - + bool + ReplaceVariables(llvm::Function &llvm_function); + /// Flags - bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved - std::string m_func_name; ///< The name of the function to translate - lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...) - lldb_private::TypeFromParser m_result_type; ///< The type of the result variable. - llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet. - std::unique_ptr<llvm::DataLayout> m_target_data; ///< The target data for the module being processed, or NULL if there is no module. - lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls - llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type - llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type - llvm::IntegerType *m_intptr_ty; ///< The type of an integer large enough to hold a pointer. - lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed - lldb_private::IRExecutionUnit &m_execution_unit; ///< The execution unit containing the IR being created. - - llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If m_has_side_effects is true, this is NULL. - bool m_result_is_pointer; ///< True if the function's result in the AST is a pointer (see comments in ASTResultSynthesizer::SynthesizeBodyResult) - - llvm::GlobalVariable *m_reloc_placeholder; ///< A placeholder that will be replaced by a pointer to the final location of the static allocation. - + bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved + lldb_private::ConstString m_func_name; ///< The name of the function to translate + lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...) + lldb_private::TypeFromParser m_result_type; ///< The type of the result variable. + llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet. + std::unique_ptr<llvm::DataLayout> + m_target_data; ///< The target data for the module being processed, or NULL if there is no module. + lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls + llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the + ///appropriate function pointer type + llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate + ///function pointer type + llvm::IntegerType *m_intptr_ty; ///< The type of an integer large enough to hold a pointer. + lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed + lldb_private::IRExecutionUnit &m_execution_unit; ///< The execution unit containing the IR being created. + + llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If + ///m_has_side_effects is true, this is NULL. + bool m_result_is_pointer; ///< True if the function's result in the AST is a pointer (see comments in + ///ASTResultSynthesizer::SynthesizeBodyResult) + + llvm::GlobalVariable *m_reloc_placeholder; ///< A placeholder that will be replaced by a pointer to the final + ///location of the static allocation. + //------------------------------------------------------------------ - /// UnfoldConstant operates on a constant [Old] which has just been - /// replaced with a value [New]. We assume that new_value has - /// been properly placed early in the function, in front of the - /// first instruction in the entry basic block - /// [FirstEntryInstruction]. + /// UnfoldConstant operates on a constant [Old] which has just been + /// replaced with a value [New]. We assume that new_value has + /// been properly placed early in the function, in front of the + /// first instruction in the entry basic block + /// [FirstEntryInstruction]. /// - /// UnfoldConstant reads through the uses of Old and replaces Old - /// in those uses with New. Where those uses are constants, the - /// function generates new instructions to compute the result of the - /// new, non-constant expression and places them before + /// UnfoldConstant reads through the uses of Old and replaces Old + /// in those uses with New. Where those uses are constants, the + /// function generates new instructions to compute the result of the + /// new, non-constant expression and places them before /// FirstEntryInstruction. These instructions replace the constant /// uses, so UnfoldConstant calls itself recursively for those. /// @@ -589,7 +594,7 @@ private: /// @return /// True on success; false otherwise //------------------------------------------------------------------ - + class FunctionValueCache { public: typedef std::function <llvm::Value *(llvm::Function *)> Maker; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits