850 lines
28 KiB
C++
Raw Normal View History

//===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===//
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
#endif
#include <cstdlib>
#include <map>
#include <string>
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
#include "ClangUserExpression.h"
#include "ASTResultSynthesizer.h"
#include "ClangDiagnostic.h"
#include "ClangExpressionDeclMap.h"
#include "ClangExpressionParser.h"
#include "ClangExpressionSourceCode.h"
#include "ClangModulesDeclVendor.h"
#include "ClangPersistentVariables.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Expression/ExpressionSourceCode.h"
#include "lldb/Expression/IRExecutionUnit.h"
This commit changes the way LLDB executes user expressions. Previously, ClangUserExpression assumed that if there was a constant result for an expression then it could be determined during parsing. In particular, the IRInterpreter ran while parser state (in particular, ClangExpressionDeclMap) was present. This approach is flawed, because the IRInterpreter actually is capable of using external variables, and hence the result might be different each run. Until now, we papered over this flaw by re-parsing the expression each time we ran it. I have rewritten the IRInterpreter to be completely independent of the ClangExpressionDeclMap. Instead of special-casing external variable lookup, which ties the IRInterpreter closely to LLDB, we now interpret the exact same IR that the JIT would see. This IR assumes that materialization has occurred; hence the recent implementation of the Materializer, which does not require parser state (in the form of ClangExpressionDeclMap) to be present. Materialization, interpretation, and dematerialization are now all independent of parsing. This means that in theory we can parse expressions once and run them many times. I have three outstanding tasks before shutting this down: - First, I will ensure that all of this works with core files. Core files have a Process but do not allow allocating memory, which currently confuses materialization. - Second, I will make expression breakpoint conditions remember their ClangUserExpression and re-use it. - Third, I will tear out all the redundant code (for example, materialization logic in ClangExpressionDeclMap) that is no longer used. While implementing this fix, I also found a bug in IRForTarget's handling of floating-point constants. This should be fixed. llvm-svn: 179801
2013-04-18 22:06:33 +00:00
#include "lldb/Expression/IRInterpreter.h"
#include "lldb/Expression/Materializer.h"
#include "lldb/Host/HostInfo.h"
<rdar://problem/11757916> Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes: - Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file". - modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly - Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was. - modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile() Cleaned up header includes a bit as well. llvm-svn: 162860
2012-08-29 21:13:06 +00:00
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Type.h"
Removed the hacky "#define this ___clang_this" handler for C++ classes. Replaced it with a less hacky approach: - If an expression is defined in the context of a method of class A, then that expression is wrapped as ___clang_class::___clang_expr(void*) { ... } instead of ___clang_expr(void*) { ... }. - ___clang_class is resolved as the type of the target of the "this" pointer in the method the expression is defined in. - When reporting the type of ___clang_class, a method with the signature ___clang_expr(void*) is added to that class, so that Clang doesn't complain about a method being defined without a corresponding declaration. - Whenever the expression gets called, "this" gets looked up, type-checked, and then passed in as the first argument. This required the following changes: - The ABIs were changed to support passing of the "this" pointer as part of trivial calls. - ThreadPlanCallFunction and ClangFunction were changed to support passing of an optional "this" pointer. - ClangUserExpression was extended to perform the wrapping described above. - ClangASTSource was changed to revert the changes required by the hack. - ClangExpressionParser, IRForTarget, and ClangExpressionDeclMap were changed to handle different manglings of ___clang_expr flexibly. This meant no longer searching for a function called ___clang_expr, but rather looking for a function whose name *contains* ___clang_expr. - ClangExpressionParser and ClangExpressionDeclMap now remember whether "this" is required, and know how to look it up as necessary. A few inheritance bugs remain, and I'm trying to resolve these. But it is now possible to use "this" as well as refer implicitly to member variables, when in the proper context. llvm-svn: 114384
2010-09-21 00:44:12 +00:00
#include "lldb/Symbol/VariableList.h"
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallUserExpression.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
using namespace lldb_private;
ClangUserExpression::ClangUserExpression(
ExecutionContextScope &exe_scope, llvm::StringRef expr,
llvm::StringRef prefix, lldb::LanguageType language,
ResultType desired_type, const EvaluateExpressionOptions &options,
ValueObject *ctx_obj)
: LLVMUserExpression(exe_scope, expr, prefix, language, desired_type,
options),
m_type_system_helper(*m_target_wp.lock(), options.GetExecutionPolicy() ==
eExecutionPolicyTopLevel),
m_result_delegate(exe_scope.CalculateTarget()), m_ctx_obj(ctx_obj) {
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;
}
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
}
ClangUserExpression::~ClangUserExpression() {}
void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
if (log)
log->Printf("ClangUserExpression::ScanContext()");
m_target = exe_ctx.GetTargetPtr();
if (!(m_allow_cxx || m_allow_objc)) {
if (log)
log->Printf(" [CUE::SC] Settings inhibit C++ and Objective-C");
return;
}
StackFrame *frame = exe_ctx.GetFramePtr();
if (frame == NULL) {
if (log)
log->Printf(" [CUE::SC] Null stack frame");
return;
}
SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
lldb::eSymbolContextBlock);
if (!sym_ctx.function) {
if (log)
log->Printf(" [CUE::SC] Null function");
return;
}
// Find the block that defines the function represented by "sym_ctx"
Block *function_block = sym_ctx.GetFunctionBlock();
if (!function_block) {
if (log)
log->Printf(" [CUE::SC] Null function block");
return;
}
CompilerDeclContext decl_context = function_block->GetDeclContext();
if (!decl_context) {
if (log)
log->Printf(" [CUE::SC] Null decl context");
return;
}
if (m_ctx_obj) {
switch (m_ctx_obj->GetObjectRuntimeLanguage()) {
case lldb::eLanguageTypeC:
case lldb::eLanguageTypeC89:
case lldb::eLanguageTypeC99:
case lldb::eLanguageTypeC11:
case lldb::eLanguageTypeC_plus_plus:
case lldb::eLanguageTypeC_plus_plus_03:
case lldb::eLanguageTypeC_plus_plus_11:
case lldb::eLanguageTypeC_plus_plus_14:
m_in_cplusplus_method = true;
break;
case lldb::eLanguageTypeObjC:
case lldb::eLanguageTypeObjC_plus_plus:
m_in_objectivec_method = true;
break;
default:
break;
}
m_needs_object_ptr = true;
} else if (clang::CXXMethodDecl *method_decl =
ClangASTContext::DeclContextGetAsCXXMethodDecl(decl_context)) {
if (m_allow_cxx && method_decl->isInstance()) {
if (m_enforce_valid_object) {
lldb::VariableListSP variable_list_sp(
function_block->GetBlockVariableList(true));
const char *thisErrorString = "Stopped in a C++ method, but 'this' "
"isn't available; pretending we are in a "
"generic context";
if (!variable_list_sp) {
err.SetErrorString(thisErrorString);
return;
}
lldb::VariableSP this_var_sp(
variable_list_sp->FindVariable(ConstString("this")));
if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
!this_var_sp->LocationIsValidForFrame(frame)) {
err.SetErrorString(thisErrorString);
return;
}
}
m_in_cplusplus_method = true;
m_needs_object_ptr = true;
}
} else if (clang::ObjCMethodDecl *method_decl =
ClangASTContext::DeclContextGetAsObjCMethodDecl(
decl_context)) {
if (m_allow_objc) {
if (m_enforce_valid_object) {
lldb::VariableListSP variable_list_sp(
function_block->GetBlockVariableList(true));
const char *selfErrorString = "Stopped in an Objective-C method, but "
"'self' isn't available; pretending we "
"are in a generic context";
if (!variable_list_sp) {
err.SetErrorString(selfErrorString);
return;
}
lldb::VariableSP self_variable_sp =
variable_list_sp->FindVariable(ConstString("self"));
if (!self_variable_sp || !self_variable_sp->IsInScope(frame) ||
!self_variable_sp->LocationIsValidForFrame(frame)) {
err.SetErrorString(selfErrorString);
return;
}
}
m_in_objectivec_method = true;
m_needs_object_ptr = true;
if (!method_decl->isInstanceMethod())
m_in_static_method = true;
}
} else if (clang::FunctionDecl *function_decl =
ClangASTContext::DeclContextGetAsFunctionDecl(decl_context)) {
// We might also have a function that said in the debug information that it
// captured an object pointer. The best way to deal with getting to the
// ivars at present is by pretending that this is a method of a class in
// whatever runtime the debug info says the object pointer belongs to. Do
// that here.
ClangASTMetadata *metadata =
ClangASTContext::DeclContextGetMetaData(decl_context, function_decl);
if (metadata && metadata->HasObjectPtr()) {
lldb::LanguageType language = metadata->GetObjectPtrLanguage();
if (language == lldb::eLanguageTypeC_plus_plus) {
if (m_enforce_valid_object) {
lldb::VariableListSP variable_list_sp(
function_block->GetBlockVariableList(true));
const char *thisErrorString = "Stopped in a context claiming to "
"capture a C++ object pointer, but "
"'this' isn't available; pretending we "
"are in a generic context";
if (!variable_list_sp) {
err.SetErrorString(thisErrorString);
return;
}
lldb::VariableSP this_var_sp(
variable_list_sp->FindVariable(ConstString("this")));
if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
!this_var_sp->LocationIsValidForFrame(frame)) {
err.SetErrorString(thisErrorString);
return;
}
}
m_in_cplusplus_method = true;
m_needs_object_ptr = true;
} else if (language == lldb::eLanguageTypeObjC) {
if (m_enforce_valid_object) {
lldb::VariableListSP variable_list_sp(
function_block->GetBlockVariableList(true));
const char *selfErrorString =
"Stopped in a context claiming to capture an Objective-C object "
"pointer, but 'self' isn't available; pretending we are in a "
"generic context";
if (!variable_list_sp) {
err.SetErrorString(selfErrorString);
return;
}
lldb::VariableSP self_variable_sp =
variable_list_sp->FindVariable(ConstString("self"));
if (!self_variable_sp || !self_variable_sp->IsInScope(frame) ||
!self_variable_sp->LocationIsValidForFrame(frame)) {
err.SetErrorString(selfErrorString);
return;
}
Type *self_type = self_variable_sp->GetType();
if (!self_type) {
err.SetErrorString(selfErrorString);
return;
}
CompilerType self_clang_type = self_type->GetForwardCompilerType();
if (!self_clang_type) {
err.SetErrorString(selfErrorString);
return;
}
if (ClangASTContext::IsObjCClassType(self_clang_type)) {
return;
} else if (ClangASTContext::IsObjCObjectPointerType(
self_clang_type)) {
m_in_objectivec_method = true;
m_needs_object_ptr = true;
} else {
err.SetErrorString(selfErrorString);
return;
}
} else {
m_in_objectivec_method = true;
m_needs_object_ptr = true;
}
}
}
}
Removed the hacky "#define this ___clang_this" handler for C++ classes. Replaced it with a less hacky approach: - If an expression is defined in the context of a method of class A, then that expression is wrapped as ___clang_class::___clang_expr(void*) { ... } instead of ___clang_expr(void*) { ... }. - ___clang_class is resolved as the type of the target of the "this" pointer in the method the expression is defined in. - When reporting the type of ___clang_class, a method with the signature ___clang_expr(void*) is added to that class, so that Clang doesn't complain about a method being defined without a corresponding declaration. - Whenever the expression gets called, "this" gets looked up, type-checked, and then passed in as the first argument. This required the following changes: - The ABIs were changed to support passing of the "this" pointer as part of trivial calls. - ThreadPlanCallFunction and ClangFunction were changed to support passing of an optional "this" pointer. - ClangUserExpression was extended to perform the wrapping described above. - ClangASTSource was changed to revert the changes required by the hack. - ClangExpressionParser, IRForTarget, and ClangExpressionDeclMap were changed to handle different manglings of ___clang_expr flexibly. This meant no longer searching for a function called ___clang_expr, but rather looking for a function whose name *contains* ___clang_expr. - ClangExpressionParser and ClangExpressionDeclMap now remember whether "this" is required, and know how to look it up as necessary. A few inheritance bugs remain, and I'm trying to resolve these. But it is now possible to use "this" as well as refer implicitly to member variables, when in the proper context. llvm-svn: 114384
2010-09-21 00:44:12 +00:00
}
// This is a really nasty hack, meant to fix Objective-C expressions of the
// form (int)[myArray count]. Right now, because the type information for
// count is not available, [myArray count] returns id, which can't be directly
// cast to int without causing a clang error.
static void ApplyObjcCastHack(std::string &expr) {
#define OBJC_CAST_HACK_FROM "(int)["
#define OBJC_CAST_HACK_TO "(int)(long long)["
size_t from_offset;
while ((from_offset = expr.find(OBJC_CAST_HACK_FROM)) != expr.npos)
expr.replace(from_offset, sizeof(OBJC_CAST_HACK_FROM) - 1,
OBJC_CAST_HACK_TO);
#undef OBJC_CAST_HACK_TO
#undef OBJC_CAST_HACK_FROM
}
namespace {
// Utility guard that calls a callback when going out of scope.
class OnExit {
public:
typedef std::function<void(void)> Callback;
OnExit(Callback const &callback) : m_callback(callback) {}
~OnExit() { m_callback(); }
private:
Callback m_callback;
};
} // namespace
bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_manager,
ExecutionContext &exe_ctx) {
if (Target *target = exe_ctx.GetTargetPtr()) {
if (PersistentExpressionState *persistent_state =
target->GetPersistentExpressionStateForLanguage(
lldb::eLanguageTypeC)) {
m_result_delegate.RegisterPersistentState(persistent_state);
} else {
diagnostic_manager.PutString(
eDiagnosticSeverityError,
"couldn't start parsing (no persistent data)");
return false;
}
} else {
diagnostic_manager.PutString(eDiagnosticSeverityError,
"error: couldn't start parsing (no target)");
return false;
}
return true;
}
static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) {
if (ClangModulesDeclVendor *decl_vendor =
target->GetClangModulesDeclVendor()) {
const ClangModulesDeclVendor::ModuleVector &hand_imported_modules =
llvm::cast<ClangPersistentVariables>(
target->GetPersistentExpressionStateForLanguage(
lldb::eLanguageTypeC))
->GetHandLoadedClangModules();
ClangModulesDeclVendor::ModuleVector modules_for_macros;
for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) {
modules_for_macros.push_back(module);
}
if (target->GetEnableAutoImportClangModules()) {
if (StackFrame *frame = exe_ctx.GetFramePtr()) {
if (Block *block = frame->GetFrameBlock()) {
SymbolContext sc;
block->CalculateSymbolContext(&sc);
if (sc.comp_unit) {
StreamString error_stream;
decl_vendor->AddModulesForCompileUnit(
*sc.comp_unit, modules_for_macros, error_stream);
}
}
}
}
}
}
void ClangUserExpression::UpdateLanguageForExpr(
DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown;
std::string prefix = m_expr_prefix;
if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
m_transformed_text = m_expr_text;
} else {
std::unique_ptr<ClangExpressionSourceCode> source_code(
ClangExpressionSourceCode::CreateWrapped(prefix.c_str(),
m_expr_text.c_str()));
if (m_in_cplusplus_method)
m_expr_lang = lldb::eLanguageTypeC_plus_plus;
else if (m_in_objectivec_method)
m_expr_lang = lldb::eLanguageTypeObjC;
Removed the hacky "#define this ___clang_this" handler for C++ classes. Replaced it with a less hacky approach: - If an expression is defined in the context of a method of class A, then that expression is wrapped as ___clang_class::___clang_expr(void*) { ... } instead of ___clang_expr(void*) { ... }. - ___clang_class is resolved as the type of the target of the "this" pointer in the method the expression is defined in. - When reporting the type of ___clang_class, a method with the signature ___clang_expr(void*) is added to that class, so that Clang doesn't complain about a method being defined without a corresponding declaration. - Whenever the expression gets called, "this" gets looked up, type-checked, and then passed in as the first argument. This required the following changes: - The ABIs were changed to support passing of the "this" pointer as part of trivial calls. - ThreadPlanCallFunction and ClangFunction were changed to support passing of an optional "this" pointer. - ClangUserExpression was extended to perform the wrapping described above. - ClangASTSource was changed to revert the changes required by the hack. - ClangExpressionParser, IRForTarget, and ClangExpressionDeclMap were changed to handle different manglings of ___clang_expr flexibly. This meant no longer searching for a function called ___clang_expr, but rather looking for a function whose name *contains* ___clang_expr. - ClangExpressionParser and ClangExpressionDeclMap now remember whether "this" is required, and know how to look it up as necessary. A few inheritance bugs remain, and I'm trying to resolve these. But it is now possible to use "this" as well as refer implicitly to member variables, when in the proper context. llvm-svn: 114384
2010-09-21 00:44:12 +00:00
else
m_expr_lang = lldb::eLanguageTypeC;
if (!source_code->GetText(m_transformed_text, m_expr_lang,
m_in_static_method, exe_ctx,
!m_ctx_obj)) {
diagnostic_manager.PutString(eDiagnosticSeverityError,
"couldn't construct expression body");
return;
Removed the hacky "#define this ___clang_this" handler for C++ classes. Replaced it with a less hacky approach: - If an expression is defined in the context of a method of class A, then that expression is wrapped as ___clang_class::___clang_expr(void*) { ... } instead of ___clang_expr(void*) { ... }. - ___clang_class is resolved as the type of the target of the "this" pointer in the method the expression is defined in. - When reporting the type of ___clang_class, a method with the signature ___clang_expr(void*) is added to that class, so that Clang doesn't complain about a method being defined without a corresponding declaration. - Whenever the expression gets called, "this" gets looked up, type-checked, and then passed in as the first argument. This required the following changes: - The ABIs were changed to support passing of the "this" pointer as part of trivial calls. - ThreadPlanCallFunction and ClangFunction were changed to support passing of an optional "this" pointer. - ClangUserExpression was extended to perform the wrapping described above. - ClangASTSource was changed to revert the changes required by the hack. - ClangExpressionParser, IRForTarget, and ClangExpressionDeclMap were changed to handle different manglings of ___clang_expr flexibly. This meant no longer searching for a function called ___clang_expr, but rather looking for a function whose name *contains* ___clang_expr. - ClangExpressionParser and ClangExpressionDeclMap now remember whether "this" is required, and know how to look it up as necessary. A few inheritance bugs remain, and I'm trying to resolve these. But it is now possible to use "this" as well as refer implicitly to member variables, when in the proper context. llvm-svn: 114384
2010-09-21 00:44:12 +00:00
}
// Find and store the start position of the original code inside the
// transformed code. We need this later for the code completion.
std::size_t original_start;
std::size_t original_end;
bool found_bounds = source_code->GetOriginalBodyBounds(
m_transformed_text, m_expr_lang, original_start, original_end);
if (found_bounds) {
m_user_expression_start_pos = original_start;
}
}
}
bool ClangUserExpression::PrepareForParsing(
DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
InstallContext(exe_ctx);
if (!SetupPersistentState(diagnostic_manager, exe_ctx))
return false;
Status err;
ScanContext(exe_ctx, err);
if (!err.Success()) {
diagnostic_manager.PutString(eDiagnosticSeverityWarning, err.AsCString());
}
////////////////////////////////////
// Generate the expression
//
ApplyObjcCastHack(m_expr_text);
SetupDeclVendor(exe_ctx, m_target);
UpdateLanguageForExpr(diagnostic_manager, exe_ctx);
return true;
}
bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy,
bool keep_result_in_memory,
bool generate_debug_info) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
if (!PrepareForParsing(diagnostic_manager, exe_ctx))
return false;
if (log)
log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str());
////////////////////////////////////
// Set up the target and compiler
//
Target *target = exe_ctx.GetTargetPtr();
if (!target) {
diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target");
return false;
}
//////////////////////////
// Parse the expression
//
m_materializer_up.reset(new Materializer());
ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory);
OnExit on_exit([this]() { ResetDeclMap(); });
if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) {
diagnostic_manager.PutString(
eDiagnosticSeverityError,
"current process state is unsuitable for expression parsing");
return false;
}
if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
DeclMap()->SetLookupsEnabled(true);
}
Process *process = exe_ctx.GetProcessPtr();
ExecutionContextScope *exe_scope = process;
if (!exe_scope)
exe_scope = exe_ctx.GetTargetPtr();
// We use a shared pointer here so we can use the original parser - if it
// succeeds or the rewrite parser we might make if it fails. But the
// parser_sp will never be empty.
ClangExpressionParser parser(exe_scope, *this, generate_debug_info);
unsigned num_errors = parser.Parse(diagnostic_manager);
// Check here for FixItHints. If there are any try to apply the fixits and
// set the fixed text in m_fixed_text before returning an error.
if (num_errors) {
if (diagnostic_manager.HasFixIts()) {
if (parser.RewriteExpression(diagnostic_manager)) {
size_t fixed_start;
size_t fixed_end;
const std::string &fixed_expression =
diagnostic_manager.GetFixedExpression();
if (ClangExpressionSourceCode::GetOriginalBodyBounds(
fixed_expression, m_expr_lang, fixed_start, fixed_end))
m_fixed_text =
fixed_expression.substr(fixed_start, fixed_end - fixed_start);
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Prepare the output of the parser for execution, evaluating it statically
// if possible
//
{
Status 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.PutString(eDiagnosticSeverityError, error_cstr);
else
diagnostic_manager.PutString(eDiagnosticSeverityError,
"expression can't be interpreted or run");
return false;
}
}
if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) {
Status 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.PutString(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 there is more than one external function in the execution unit, it
// needs to keep living even if it's not top level, because the result
// could refer to that function.
if (m_execution_unit_sp->GetJittedFunctions().size() > 1) {
register_execution_unit = true;
}
if (register_execution_unit) {
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());
if (jit_module_sp) {
ConstString const_func_name(FunctionName());
FileSpec jit_file;
jit_file.GetFilename() = const_func_name;
jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());
m_jit_module_wp = jit_module_sp;
target->GetImages().Append(jit_module_sp);
}
}
if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS)
m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
return true;
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
}
//------------------------------------------------------------------
/// Converts an absolute position inside a given code string into
/// a column/line pair.
///
/// @param[in] abs_pos
/// A absolute position in the code string that we want to convert
/// to a column/line pair.
///
/// @param[in] code
/// A multi-line string usually representing source code.
///
/// @param[out] line
/// The line in the code that contains the given absolute position.
/// The first line in the string is indexed as 1.
///
/// @param[out] column
/// The column in the line that contains the absolute position.
/// The first character in a line is indexed as 0.
//------------------------------------------------------------------
static void AbsPosToLineColumnPos(size_t abs_pos, llvm::StringRef code,
unsigned &line, unsigned &column) {
// Reset to code position to beginning of the file.
line = 0;
column = 0;
assert(abs_pos <= code.size() && "Absolute position outside code string?");
// We have to walk up to the position and count lines/columns.
for (std::size_t i = 0; i < abs_pos; ++i) {
// If we hit a line break, we go back to column 0 and enter a new line.
// We only handle \n because that's what we internally use to make new
// lines for our temporary code strings.
if (code[i] == '\n') {
++line;
column = 0;
continue;
}
++column;
}
}
bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,
CompletionRequest &request,
unsigned complete_pos) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
// We don't want any visible feedback when completing an expression. Mostly
// because the results we get from an incomplete invocation are probably not
// correct.
DiagnosticManager diagnostic_manager;
if (!PrepareForParsing(diagnostic_manager, exe_ctx))
return false;
if (log)
log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str());
//////////////////////////
// Parse the expression
//
m_materializer_up.reset(new Materializer());
ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true);
OnExit on_exit([this]() { ResetDeclMap(); });
if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) {
diagnostic_manager.PutString(
eDiagnosticSeverityError,
"current process state is unsuitable for expression parsing");
return false;
}
if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
DeclMap()->SetLookupsEnabled(true);
}
Process *process = exe_ctx.GetProcessPtr();
ExecutionContextScope *exe_scope = process;
if (!exe_scope)
exe_scope = exe_ctx.GetTargetPtr();
ClangExpressionParser parser(exe_scope, *this, false);
// We have to find the source code location where the user text is inside
// the transformed expression code. When creating the transformed text, we
// already stored the absolute position in the m_transformed_text string. The
// only thing left to do is to transform it into the line:column format that
// Clang expects.
// The line and column of the user expression inside the transformed source
// code.
unsigned user_expr_line, user_expr_column;
if (m_user_expression_start_pos.hasValue())
AbsPosToLineColumnPos(*m_user_expression_start_pos, m_transformed_text,
user_expr_line, user_expr_column);
else
return false;
// The actual column where we have to complete is the start column of the
// user expression + the offset inside the user code that we were given.
const unsigned completion_column = user_expr_column + complete_pos;
parser.Complete(request, user_expr_line, completion_column, complete_pos);
return true;
}
bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx,
std::vector<lldb::addr_t> &args,
lldb::addr_t struct_address,
DiagnosticManager &diagnostic_manager) {
lldb::addr_t object_ptr = LLDB_INVALID_ADDRESS;
lldb::addr_t cmd_ptr = LLDB_INVALID_ADDRESS;
if (m_needs_object_ptr) {
lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP();
if (!frame_sp)
return true;
ConstString object_name;
if (m_in_cplusplus_method) {
object_name.SetCString("this");
} else if (m_in_objectivec_method) {
object_name.SetCString("self");
} else {
diagnostic_manager.PutString(
eDiagnosticSeverityError,
"need object pointer but don't know the language");
return false;
}
Status object_ptr_error;
if (m_ctx_obj) {
AddressType address_type;
object_ptr = m_ctx_obj->GetAddressOf(false, &address_type);
if (object_ptr == LLDB_INVALID_ADDRESS ||
address_type != eAddressTypeLoad)
object_ptr_error.SetErrorString("Can't get context object's "
"debuggee address");
} else
object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
if (!object_ptr_error.Success()) {
exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf(
2017-02-21 05:09:26 +00:00
"warning: `%s' is not accessible (substituting 0)\n",
object_name.AsCString());
object_ptr = 0;
}
if (m_in_objectivec_method) {
ConstString cmd_name("_cmd");
cmd_ptr = GetObjectPointer(frame_sp, cmd_name, object_ptr_error);
if (!object_ptr_error.Success()) {
diagnostic_manager.Printf(
eDiagnosticSeverityWarning,
"couldn't get cmd pointer (substituting NULL): %s",
object_ptr_error.AsCString());
cmd_ptr = 0;
}
}
This commit changes the way LLDB executes user expressions. Previously, ClangUserExpression assumed that if there was a constant result for an expression then it could be determined during parsing. In particular, the IRInterpreter ran while parser state (in particular, ClangExpressionDeclMap) was present. This approach is flawed, because the IRInterpreter actually is capable of using external variables, and hence the result might be different each run. Until now, we papered over this flaw by re-parsing the expression each time we ran it. I have rewritten the IRInterpreter to be completely independent of the ClangExpressionDeclMap. Instead of special-casing external variable lookup, which ties the IRInterpreter closely to LLDB, we now interpret the exact same IR that the JIT would see. This IR assumes that materialization has occurred; hence the recent implementation of the Materializer, which does not require parser state (in the form of ClangExpressionDeclMap) to be present. Materialization, interpretation, and dematerialization are now all independent of parsing. This means that in theory we can parse expressions once and run them many times. I have three outstanding tasks before shutting this down: - First, I will ensure that all of this works with core files. Core files have a Process but do not allow allocating memory, which currently confuses materialization. - Second, I will make expression breakpoint conditions remember their ClangUserExpression and re-use it. - Third, I will tear out all the redundant code (for example, materialization logic in ClangExpressionDeclMap) that is no longer used. While implementing this fix, I also found a bug in IRForTarget's handling of floating-point constants. This should be fixed. llvm-svn: 179801
2013-04-18 22:06:33 +00:00
args.push_back(object_ptr);
This commit changes the way LLDB executes user expressions. Previously, ClangUserExpression assumed that if there was a constant result for an expression then it could be determined during parsing. In particular, the IRInterpreter ran while parser state (in particular, ClangExpressionDeclMap) was present. This approach is flawed, because the IRInterpreter actually is capable of using external variables, and hence the result might be different each run. Until now, we papered over this flaw by re-parsing the expression each time we ran it. I have rewritten the IRInterpreter to be completely independent of the ClangExpressionDeclMap. Instead of special-casing external variable lookup, which ties the IRInterpreter closely to LLDB, we now interpret the exact same IR that the JIT would see. This IR assumes that materialization has occurred; hence the recent implementation of the Materializer, which does not require parser state (in the form of ClangExpressionDeclMap) to be present. Materialization, interpretation, and dematerialization are now all independent of parsing. This means that in theory we can parse expressions once and run them many times. I have three outstanding tasks before shutting this down: - First, I will ensure that all of this works with core files. Core files have a Process but do not allow allocating memory, which currently confuses materialization. - Second, I will make expression breakpoint conditions remember their ClangUserExpression and re-use it. - Third, I will tear out all the redundant code (for example, materialization logic in ClangExpressionDeclMap) that is no longer used. While implementing this fix, I also found a bug in IRForTarget's handling of floating-point constants. This should be fixed. llvm-svn: 179801
2013-04-18 22:06:33 +00:00
if (m_in_objectivec_method)
args.push_back(cmd_ptr);
args.push_back(struct_address);
} else {
args.push_back(struct_address);
}
return true;
This is a major refactoring of the expression parser. The goal is to separate the parser's data from the data belonging to the parser's clients. This allows clients to use the parser to obtain (for example) a JIT compiled function or some DWARF code, and then discard the parser state. Previously, parser state was held in ClangExpression and used liberally by ClangFunction, which inherited from ClangExpression. The main effects of this refactoring are: - reducing ClangExpression to an abstract class that declares methods that any client must expose to the expression parser, - moving the code specific to implementing the "expr" command from ClangExpression and CommandObjectExpression into ClangUserExpression, a new class, - moving the common parser interaction code from ClangExpression into ClangExpressionParser, a new class, and - making ClangFunction rely only on ClangExpressionParser and not depend on the internal implementation of ClangExpression. Side effects include: - the compiler interaction code has been factored out of ClangFunction and is now in an AST pass (ASTStructExtractor), - the header file for ClangFunction is now fully documented, - several bugs that only popped up when Clang was deallocated (which never happened, since the lifetime of the compiler was essentially infinite) are now fixed, and - the developer-only "call" command has been disabled. I have tested the expr command and the Objective-C step-into code, which use ClangUserExpression and ClangFunction, respectively, and verified that they work. Please let me know if you encounter bugs or poor documentation. llvm-svn: 112249
2010-08-27 01:01:44 +00:00
}
lldb::ExpressionVariableSP ClangUserExpression::GetResultAfterDematerialization(
ExecutionContextScope *exe_scope) {
return m_result_delegate.GetVariable();
}
void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(
ExecutionContext &exe_ctx,
Materializer::PersistentVariableDelegate &delegate,
bool keep_result_in_memory,
ValueObject *ctx_obj) {
m_expr_decl_map_up.reset(
new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx,
ctx_obj));
This patch makes Clang-independent base classes for all the expression types that lldb currently vends. Before we had: ClangFunction ClangUtilityFunction ClangUserExpression and code all over in lldb that explicitly made Clang-based expressions. This patch adds an Expression base class, and three pure virtual implementations for the Expression kinds: FunctionCaller UtilityFunction UserExpression You can request one of these expression types from the Target using the Get<ExpressionType>ForLanguage. The Target will then consult all the registered TypeSystem plugins, and if the type system that matches the language can make an expression of that kind, it will do so and return it. Because all of the real expression types need to communicate with their ExpressionParser in a uniform way, I also added a ExpressionTypeSystemHelper class that expressions generically can vend, and a ClangExpressionHelper that encapsulates the operations that the ClangExpressionParser needs to perform on the ClangExpression types. Then each of the Clang* expression kinds constructs the appropriate helper to do what it needs. The patch also fixes a wart in the UtilityFunction that to use it you had to create a parallel FunctionCaller to actually call the function made by the UtilityFunction. Now the UtilityFunction can be asked to vend a FunctionCaller that will run its function. This cleaned up a lot of boiler plate code using UtilityFunctions. Note, in this patch all the expression types explicitly depend on the LLVM JIT and IR, and all the common JIT running code is in the FunctionCaller etc base classes. At some point we could also abstract that dependency but I don't see us adding another back end in the near term, so I'll leave that exercise till it is actually necessary. llvm-svn: 247720
2015-09-15 21:13:50 +00:00
}
This patch makes Clang-independent base classes for all the expression types that lldb currently vends. Before we had: ClangFunction ClangUtilityFunction ClangUserExpression and code all over in lldb that explicitly made Clang-based expressions. This patch adds an Expression base class, and three pure virtual implementations for the Expression kinds: FunctionCaller UtilityFunction UserExpression You can request one of these expression types from the Target using the Get<ExpressionType>ForLanguage. The Target will then consult all the registered TypeSystem plugins, and if the type system that matches the language can make an expression of that kind, it will do so and return it. Because all of the real expression types need to communicate with their ExpressionParser in a uniform way, I also added a ExpressionTypeSystemHelper class that expressions generically can vend, and a ClangExpressionHelper that encapsulates the operations that the ClangExpressionParser needs to perform on the ClangExpression types. Then each of the Clang* expression kinds constructs the appropriate helper to do what it needs. The patch also fixes a wart in the UtilityFunction that to use it you had to create a parallel FunctionCaller to actually call the function made by the UtilityFunction. Now the UtilityFunction can be asked to vend a FunctionCaller that will run its function. This cleaned up a lot of boiler plate code using UtilityFunctions. Note, in this patch all the expression types explicitly depend on the LLVM JIT and IR, and all the common JIT running code is in the FunctionCaller etc base classes. At some point we could also abstract that dependency but I don't see us adding another back end in the near term, so I'll leave that exercise till it is actually necessary. llvm-svn: 247720
2015-09-15 21:13:50 +00:00
clang::ASTConsumer *
ClangUserExpression::ClangUserExpressionHelper::ASTTransformer(
clang::ASTConsumer *passthrough) {
m_result_synthesizer_up.reset(
new ASTResultSynthesizer(passthrough, m_top_level, m_target));
return m_result_synthesizer_up.get();
}
This patch makes Clang-independent base classes for all the expression types that lldb currently vends. Before we had: ClangFunction ClangUtilityFunction ClangUserExpression and code all over in lldb that explicitly made Clang-based expressions. This patch adds an Expression base class, and three pure virtual implementations for the Expression kinds: FunctionCaller UtilityFunction UserExpression You can request one of these expression types from the Target using the Get<ExpressionType>ForLanguage. The Target will then consult all the registered TypeSystem plugins, and if the type system that matches the language can make an expression of that kind, it will do so and return it. Because all of the real expression types need to communicate with their ExpressionParser in a uniform way, I also added a ExpressionTypeSystemHelper class that expressions generically can vend, and a ClangExpressionHelper that encapsulates the operations that the ClangExpressionParser needs to perform on the ClangExpression types. Then each of the Clang* expression kinds constructs the appropriate helper to do what it needs. The patch also fixes a wart in the UtilityFunction that to use it you had to create a parallel FunctionCaller to actually call the function made by the UtilityFunction. Now the UtilityFunction can be asked to vend a FunctionCaller that will run its function. This cleaned up a lot of boiler plate code using UtilityFunctions. Note, in this patch all the expression types explicitly depend on the LLVM JIT and IR, and all the common JIT running code is in the FunctionCaller etc base classes. At some point we could also abstract that dependency but I don't see us adding another back end in the near term, so I'll leave that exercise till it is actually necessary. llvm-svn: 247720
2015-09-15 21:13:50 +00:00
void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() {
if (m_result_synthesizer_up) {
m_result_synthesizer_up->CommitPersistentDecls();
}
}
ConstString ClangUserExpression::ResultDelegate::GetName() {
auto prefix = m_persistent_state->GetPersistentVariablePrefix();
return m_persistent_state->GetNextPersistentVariableName(*m_target_sp,
prefix);
}
void ClangUserExpression::ResultDelegate::DidDematerialize(
lldb::ExpressionVariableSP &variable) {
m_variable = variable;
}
void ClangUserExpression::ResultDelegate::RegisterPersistentState(
PersistentExpressionState *persistent_state) {
m_persistent_state = persistent_state;
}
lldb::ExpressionVariableSP &ClangUserExpression::ResultDelegate::GetVariable() {
return m_variable;
}