Documented ClangExpression and made parts of it

more sane (i.e., removed dead arguments, made
sensible defaults, etc.)

llvm-svn: 110990
This commit is contained in:
Sean Callanan 2010-08-13 00:28:39 +00:00
parent e7c1fe6ab7
commit b269b6eabb
4 changed files with 196 additions and 125 deletions

View File

@ -35,94 +35,252 @@ namespace lldb_private {
class RecordingMemoryManager;
//----------------------------------------------------------------------
/// @class ClangExpression ClangExpression.h "lldb/Expression/ClangExpression.h"
/// @brief Encapsulates a single expression for use with Clang
///
/// LLDB uses expressions for various purposes, notably to call functions
/// and as a backend for the expr command. ClangExpression encapsulates
/// the objects needed to parse and interpret or JIT an expression. It
/// uses the Clang parser to produce LLVM IR from the expression.
//----------------------------------------------------------------------
class ClangExpression
{
public:
//------------------------------------------------------------------
// Constructors and Destructors
/// Constructor
///
/// Initializes class variabes.
///
/// @param[in] target_triple
/// The LLVM-friendly target triple for use in initializing the
/// compiler.
///
/// @param[in] expr_decl_map
/// The object that looks up externally-defined names in LLDB's
/// debug information.
//------------------------------------------------------------------
ClangExpression(const char *target_triple,
ClangExpressionDeclMap *expr_decl_map);
//------------------------------------------------------------------
/// Destructor
//------------------------------------------------------------------
~ClangExpression();
unsigned Compile();
//------------------------------------------------------------------
/// Parse a single expression and convert it to IR using Clang. Wrap
/// the expression in a function with signature void ___clang_expr(void*).
///
/// @param[in] expr_text
/// The text of the expression to be parsed.
///
/// @param[in] stream
/// The stream to print errors to.
///
/// @param[in] add_result_var
/// True if a special result variable should be generated for
/// the expression.
///
/// @return
/// The number of errors encountered during parsing. 0 means
/// success.
//------------------------------------------------------------------
unsigned
ParseExpression (const char *expr_text,
Stream &stream,
bool add_result_var = false);
//------------------------------------------------------------------
/// Parse a single expression and convert it to IR using Clang. Don't
/// wrap the expression in anything at all.
///
/// @param[in] expr_text
/// The text of the expression to be parsed.
///
/// @param[in] stream
/// The stream to print errors to.
///
/// @param[in] add_result_var
/// True if a special result variable should be generated for
/// the expression.
///
/// @return
/// The number of errors encountered during parsing. 0 means
/// success.
//------------------------------------------------------------------
unsigned
ParseBareExpression (llvm::StringRef expr_text,
Stream &stream,
bool add_result_var = false);
//------------------------------------------------------------------
/// Convert the IR for an already-parsed expression to DWARF if possible.
///
/// @param[in] expr_local_variable_list
/// The list of local variables the expression uses, with types, for
/// use by the DWARF parser.
///
/// @param[in] dwarf_opcode_strm
/// The stream to place the resulting DWARF code into.
///
/// @return
/// True on success; false on failure. On failure, it may be appropriate
/// to call PrepareIRForTarget().
//------------------------------------------------------------------
bool
ConvertIRToDWARF (ClangExpressionVariableList &excpr_local_variable_list,
StreamString &dwarf_opcode_strm);
//------------------------------------------------------------------
/// Prepare the IR for an already-parsed expression for execution in the
/// target process by (among other things) making all externally-defined
/// variables point to offsets from the void* argument.
///
/// @return
/// True on success; false on failure. On failure, this expression
/// cannot be executed by LLDB.
//------------------------------------------------------------------
bool
PrepareIRForTarget (ClangExpressionVariableList &excpr_local_variable_list);
PrepareIRForTarget ();
//------------------------------------------------------------------
/// Use the JIT to compile an already-prepared expression from IR into
/// machine code, but keep the code in the current process for now.
///
/// @param[in] func_name
/// The name of the function to be JITted. By default, the function
/// wrapped by ParseExpression().
///
/// @return
/// True on success; false otherwise.
//------------------------------------------------------------------
bool
JITFunction (const ExecutionContext &exc_context, const char *func_name);
JITFunction (const char *func_name = "___clang_expr");
//------------------------------------------------------------------
/// Write the machine code generated by the JIT into the target's memory.
///
/// @param[in] exc_context
/// The execution context that the JITted code must be copied into.
///
/// @return
/// True on success; false otherwise.
//------------------------------------------------------------------
bool
WriteJITCode (const ExecutionContext &exc_context);
//------------------------------------------------------------------
/// Write the machine code generated by the JIT into the target process.
///
/// @param[in] func_name
/// The name of the function whose address is being requested.
/// By default, the function wrapped by ParseExpression().
///
/// @return
/// True on success; false otherwise.
//------------------------------------------------------------------
lldb::addr_t
GetFunctionAddress (const char *name);
GetFunctionAddress (const char *func_name = "___clang_expr");
//------------------------------------------------------------------
/// Disassemble the machine code for a JITted function from the target
/// process's memory and print the result to a stream.
///
/// @param[in] stream
/// The stream to print disassembly to.
///
/// @param[in] exc_context
/// The execution context to get the machine code from.
///
/// @param[in] func_name
/// The name of the function to be disassembled. By default, the
/// function wrapped by ParseExpression().
///
/// @return
/// The error generated. If .Success() is true, disassembly succeeded.
//------------------------------------------------------------------
Error
DisassembleFunction (Stream &stream, ExecutionContext &exc_context, const char *name);
DisassembleFunction (Stream &stream, ExecutionContext &exc_context, const char *func_name = "___clang_expr");
//------------------------------------------------------------------
/// Return the Clang compiler instance being used by this expression.
//------------------------------------------------------------------
clang::CompilerInstance *
GetCompilerInstance ()
{
return m_clang_ap.get();
}
//------------------------------------------------------------------
/// Return the AST context being used by this expression.
//------------------------------------------------------------------
clang::ASTContext *
GetASTContext ();
//------------------------------------------------------------------
/// Return the mutex being used to serialize access to Clang.
//------------------------------------------------------------------
static Mutex &
GetClangMutex ();
protected:
// This class is a pass-through for the default JIT memory manager,
// which just records the memory regions that were handed out so we
// can copy them into the target later on.
//------------------------------------------------------------------
// Classes that inherit from ClangExpression can see and modify these
//------------------------------------------------------------------
//----------------------------------------------------------------------
/// @class JittedFunction ClangExpression.h "lldb/Expression/ClangExpression.h"
/// @brief Encapsulates a single function that has been generated by the JIT.
///
/// Functions that have been generated by the JIT are first resident in the
/// local process, and then placed in the target process. JittedFunction
/// represents a function possibly resident in both.
//----------------------------------------------------------------------
struct JittedFunction {
std::string m_name;
lldb::addr_t m_local_addr;
lldb::addr_t m_remote_addr;
std::string m_name; ///< The function's name
lldb::addr_t m_local_addr; ///< The address of the function in LLDB's memory
lldb::addr_t m_remote_addr; ///< The address of the function in the target's memory
//------------------------------------------------------------------
/// Constructor
///
/// Initializes class variabes.
///
/// @param[in] name
/// The name of the function.
///
/// @param[in] local_addr
/// The address of the function in LLDB, or LLDB_INVALID_ADDRESS if
/// it is not present in LLDB's memory.
///
/// @param[in] remote_addr
/// The address of the function in the target, or LLDB_INVALID_ADDRESS
/// if it is not present in the target's memory.
//------------------------------------------------------------------
JittedFunction (const char *name,
lldb::addr_t local_addr = LLDB_INVALID_ADDRESS,
lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) :
lldb::addr_t local_addr = LLDB_INVALID_ADDRESS,
lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) :
m_name (name),
m_local_addr (local_addr),
m_remote_addr (remote_addr) {}
};
std::string m_target_triple;
ClangExpressionDeclMap *m_decl_map;
std::auto_ptr<clang::CompilerInstance> m_clang_ap;
clang::CodeGenerator *m_code_generator_ptr; // This will be deleted by the Execution Engine.
RecordingMemoryManager *m_jit_mm_ptr; // This will be deleted by the Execution Engine.
std::auto_ptr<llvm::ExecutionEngine> m_execution_engine;
std::vector<JittedFunction> m_jitted_functions;
std::string m_target_triple; ///< The target triple used to initialize LLVM
ClangExpressionDeclMap *m_decl_map; ///< The class used to look up entities defined in the debug info
std::auto_ptr<clang::CompilerInstance> m_clang_ap; ///< The Clang compiler used to parse expressions into IR
clang::CodeGenerator *m_code_generator_ptr; ///< [owned by the Execution Engine] The Clang object that generates IR
RecordingMemoryManager *m_jit_mm_ptr; ///< [owned by the Execution Engine] The memory manager that allocates code pages on the JIT's behalf
std::auto_ptr<llvm::ExecutionEngine> m_execution_engine; ///< The LLVM JIT
std::vector<JittedFunction> m_jitted_functions; ///< A vector of all functions that have been JITted into machine code (just one, if ParseExpression() was called)
private:
bool CreateCompilerInstance(bool &IsAST);
//------------------------------------------------------------------
/// Initialize m_clang_ap to a compiler instance with all the options
/// required by the expression parser.
///
/// @return
/// True on success; false otherwise.
//------------------------------------------------------------------
bool CreateCompilerInstance();
//------------------------------------------------------------------
// For ClangExpression only

View File

@ -267,7 +267,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
{
if (log)
log->Printf("Code cannot be interpreted and must be run in the target.");
success = clang_expr.PrepareIRForTarget (expr_local_vars);
success = clang_expr.PrepareIRForTarget ();
}
if (!success)
@ -283,7 +283,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
}
else
{
if (!clang_expr.JITFunction (m_exe_ctx, "___clang_expr"))
if (!clang_expr.JITFunction ())
{
error_stream.PutCString ("error: IR could not be JIT compiled\n");
return false;
@ -295,7 +295,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
return false;
}
lldb::addr_t function_address(clang_expr.GetFunctionAddress ("___clang_expr"));
lldb::addr_t function_address(clang_expr.GetFunctionAddress ());
if (function_address == LLDB_INVALID_ADDRESS)
{
@ -318,7 +318,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
StreamString insns;
Error err = clang_expr.DisassembleFunction(insns, m_exe_ctx, "___clang_expr");
Error err = clang_expr.DisassembleFunction(insns, m_exe_ctx);
if (!err.Success())
{

View File

@ -217,7 +217,7 @@ ClangExpression::~ClangExpression()
}
bool
ClangExpression::CreateCompilerInstance (bool &IsAST)
ClangExpression::CreateCompilerInstance ()
{
// Initialize targets first, so that --version shows registered targets.
static struct InitializeLLVM {
@ -313,8 +313,7 @@ ClangExpression::ParseBareExpression (llvm::StringRef expr_text,
TextDiagnosticBuffer text_diagnostic_buffer;
bool IsAST = false;
if (!CreateCompilerInstance (IsAST))
if (!CreateCompilerInstance ())
{
stream.Printf("error: couldn't create compiler instance\n");
return 1;
@ -462,7 +461,7 @@ ClangExpression::ConvertIRToDWARF (ClangExpressionVariableList &expr_local_varia
}
bool
ClangExpression::PrepareIRForTarget (ClangExpressionVariableList &expr_local_variable_list)
ClangExpression::PrepareIRForTarget ()
{
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
@ -498,7 +497,7 @@ ClangExpression::PrepareIRForTarget (ClangExpressionVariableList &expr_local_var
}
bool
ClangExpression::JITFunction (const ExecutionContext &exc_context, const char *name)
ClangExpression::JITFunction (const char *name)
{
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
@ -747,89 +746,3 @@ ClangExpression::DisassembleFunction (Stream &stream, ExecutionContext &exe_ctx,
return ret;
}
unsigned
ClangExpression::Compile()
{
Mutex::Locker locker(GetClangMutex ());
bool IsAST = false;
if (CreateCompilerInstance(IsAST))
{
// Validate/process some options
if (m_clang_ap->getHeaderSearchOpts().Verbose)
llvm::errs() << "clang-cc version " CLANG_VERSION_STRING
<< " based upon " << PACKAGE_STRING
<< " hosted on " << llvm::sys::getHostTriple() << "\n";
// Enforce certain implications.
if (!m_clang_ap->getFrontendOpts().ViewClassInheritance.empty())
m_clang_ap->getFrontendOpts().ProgramAction = frontend::InheritanceView;
// if (!compiler_instance->getFrontendOpts().FixItSuffix.empty())
// compiler_instance->getFrontendOpts().ProgramAction = frontend::FixIt;
for (unsigned i = 0, e = m_clang_ap->getFrontendOpts().Inputs.size(); i != e; ++i) {
// If we aren't using an AST file, setup the file and source managers and
// the preprocessor.
if (!IsAST) {
if (!i) {
// Create a file manager object to provide access to and cache the
// filesystem.
m_clang_ap->createFileManager();
// Create the source manager.
m_clang_ap->createSourceManager();
} else {
// Reset the ID tables if we are reusing the SourceManager.
m_clang_ap->getSourceManager().clearIDTables();
}
// Create the preprocessor.
m_clang_ap->createPreprocessor();
}
llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(*m_clang_ap.get()));
if (!Act)
break;
if (Act->BeginSourceFile(*m_clang_ap,
m_clang_ap->getFrontendOpts().Inputs[i].second,
m_clang_ap->getFrontendOpts().Inputs[i].first)) {
Act->Execute();
Act->EndSourceFile();
}
}
if (m_clang_ap->getDiagnosticOpts().ShowCarets)
{
unsigned NumWarnings = m_clang_ap->getDiagnostics().getNumWarnings();
unsigned NumErrors = m_clang_ap->getDiagnostics().getNumErrors() -
m_clang_ap->getDiagnostics().getNumErrorsSuppressed();
if (NumWarnings || NumErrors)
{
if (NumWarnings)
fprintf (stderr, "%u warning%s%s", NumWarnings, (NumWarnings == 1 ? "" : "s"), (NumErrors ? " and " : ""));
if (NumErrors)
fprintf (stderr, "%u error%s", NumErrors, (NumErrors == 1 ? "" : "s"));
fprintf (stderr, " generated.\n");
}
}
if (m_clang_ap->getFrontendOpts().ShowStats) {
m_clang_ap->getFileManager().PrintStats();
fprintf(stderr, "\n");
}
// Return the appropriate status when verifying diagnostics.
//
// FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
// this.
if (m_clang_ap->getDiagnosticOpts().VerifyDiagnostics)
return static_cast<VerifyDiagnosticsClient&>(m_clang_ap->getDiagnosticClient()).HadErrors();
return m_clang_ap->getDiagnostics().getNumErrors();
}
return 1;
}

View File

@ -258,7 +258,7 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
if (!m_JITted)
{
// Next we should JIT it and insert the result into the target program.
if (!JITFunction (exe_ctx, m_wrapper_function_name.c_str()))
if (!JITFunction (m_wrapper_function_name.c_str()))
return false;
if (!WriteJITCode (exe_ctx))