Wrote the code that looks at a context to see
if the variables in that context allow a particular
JIT compiled expression to run in that context.


git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@108485 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
index b83cf4a..b0f1cf2 100644
--- a/source/Expression/ClangExpressionDeclMap.cpp
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -15,6 +15,7 @@
 // Project includes
 #include "lldb/lldb-private.h"
 #include "lldb/Core/Address.h"
+#include "lldb/Core/Error.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Expression/ClangASTSource.h"
@@ -27,19 +28,17 @@
 #include "lldb/Symbol/TypeList.h"
 #include "lldb/Symbol/Variable.h"
 #include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Process.h"
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Target/ExecutionContext.h"
 
-#define DEBUG_PRINTF(...)           \
-    if (log)                        \
-        log->Printf(__VA_ARGS__)
-
 using namespace lldb_private;
 using namespace clang;
 
 ClangExpressionDeclMap::ClangExpressionDeclMap(ExecutionContext *exe_ctx) :
     m_exe_ctx(exe_ctx),
-    m_struct_laid_out(false)
+    m_struct_laid_out(false),
+    m_materialized_location(0)
 {
     if (exe_ctx && exe_ctx->frame)
         m_sym_ctx = new SymbolContext(exe_ctx->frame->GetSymbolContext(lldb::eSymbolContextEverything));
@@ -83,6 +82,8 @@
 bool 
 ClangExpressionDeclMap::AddValueToStruct (llvm::Value *value,
                                           const clang::NamedDecl *decl,
+                                          std::string &name,
+                                          void *type,
                                           size_t size,
                                           off_t alignment)
 {
@@ -102,6 +103,8 @@
     
     member.m_value      = value;
     member.m_decl       = decl;
+    member.m_name       = name;
+    member.m_type       = type;
     member.m_offset     = 0;
     member.m_size       = size;
     member.m_alignment  = alignment;
@@ -187,6 +190,136 @@
     return m_tuples[index].m_value;
 }
 
+// Interface for CommandObjectExpression
+lldb::addr_t 
+ClangExpressionDeclMap::Materialize (ExecutionContext *exe_ctx, Error &err)
+{
+    if (!m_struct_laid_out)
+    {
+        err.SetErrorString("Structure hasn't been laid out yet");
+        return LLDB_INVALID_ADDRESS;
+    }
+    
+    if (m_materialized_location)
+    {
+        exe_ctx->process->DeallocateMemory(m_materialized_location);
+        m_materialized_location = 0;
+    }
+    
+    if (!exe_ctx)
+    {
+        err.SetErrorString("Received null execution context");
+        return LLDB_INVALID_ADDRESS;
+    }
+    
+    const SymbolContext &sym_ctx(exe_ctx->frame->GetSymbolContext(lldb::eSymbolContextEverything));
+    
+    StructMemberIterator iter;
+        
+    lldb::addr_t mem = exe_ctx->process->AllocateMemory(m_struct_alignment + m_struct_size, 
+                                                        lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+                                                        err);
+    
+    if (mem == LLDB_INVALID_ADDRESS)
+        return LLDB_INVALID_ADDRESS;
+    
+    m_materialized_location = mem;
+    
+    lldb::addr_t aligned_mem = mem;
+    
+    if (aligned_mem % m_struct_alignment)
+    {
+        aligned_mem += (m_struct_alignment - (aligned_mem % m_struct_alignment));
+    }
+    
+    for (iter = m_members.begin();
+         iter != m_members.end();
+         ++iter)
+    {
+        uint32_t tuple_index;
+        
+        if (!GetIndexForDecl(tuple_index, iter->m_decl))
+            continue;
+        
+        Tuple &tuple(m_tuples[tuple_index]);
+        
+        MaterializeOneVariable(*exe_ctx, sym_ctx, iter->m_name.c_str(), tuple.m_orig_type, tuple.m_ast_context, aligned_mem + iter->m_offset);
+    }
+    
+    return aligned_mem;
+}
+
+bool 
+ClangExpressionDeclMap::MaterializeOneVariable(ExecutionContext &exe_ctx,
+                                               const SymbolContext &sym_ctx,
+                                               const char *name,
+                                               void *type,
+                                               clang::ASTContext *ast_context,
+                                               lldb::addr_t addr)
+{
+    Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+
+    Function *function(m_sym_ctx->function);
+    Block *block(m_sym_ctx->block);
+    
+    if (!function || !block)
+    {
+        if (log)
+            log->Printf("function = %p, block = %p", function, block);
+        return false;
+    }
+    
+    BlockList& blocks(function->GetBlocks(true));
+    
+    lldb::user_id_t current_block_id;
+    
+    for (current_block_id = block->GetID();
+         current_block_id != Block::InvalidID;
+         current_block_id = blocks.GetParent(current_block_id))
+    {
+        Block *current_block(blocks.GetBlockByID(current_block_id));
+        
+        lldb::VariableListSP var_list = current_block->GetVariableList(false, true);
+        
+        if (!var_list)
+            continue;
+        
+        lldb::VariableSP var = var_list->FindVariable(ConstString(name));
+        
+        if (!var)
+            continue;
+        
+        // var->GetType()->GetClangAST() is the program's AST context and holds
+        // var->GetType()->GetOpaqueClangQualType().
+        
+        // type is m_type for one of the struct members, which was added by 
+        // AddValueToStruct.  That type was extracted from the AST context of
+        // the compiler in IRForTarget.  The original for the type was copied
+        // out of the program's AST context by AddOneVariable.
+        
+        // The key here is: we know when we copied a type, and for what Decl we
+        // did it.  So we need for each struct Tuple to keep the type that we
+        // found, and which AST context we found it in. Then we can look up
+        // m_decl in m_tuples.
+        
+        if (ast_context == var->GetType()->GetClangAST())
+        {
+            if (!ClangASTContext::AreTypesSame(ast_context, type, var->GetType()->GetOpaqueClangQualType()))
+                continue;
+        }
+        else
+        {
+            if (log)
+                log->PutCString("Skipping a candidate variable because of different AST contexts");
+            continue;
+        }
+        
+        
+    }
+    
+    return true;
+}
+
 // Interface for ClangASTSource
 void 
 ClangExpressionDeclMap::GetDecls(NameSearchContext &context,
@@ -194,7 +327,8 @@
 {
     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
     
-    DEBUG_PRINTF("Hunting for a definition for %s", name);
+    if (log)
+        log->Printf("Hunting for a definition for %s", name);
     
     // Back out in all cases where we're not fully initialized
     if (!m_exe_ctx || !m_exe_ctx->frame || !m_sym_ctx)
@@ -205,7 +339,8 @@
     
     if (!function || !block)
     {
-        DEBUG_PRINTF("function = %p, block = %p", function, block);
+        if (log)
+            log->Printf("function = %p, block = %p", function, block);
         return;
     }
     
@@ -247,7 +382,8 @@
         
         if (!compile_unit)
         {
-            DEBUG_PRINTF("compile_unit = %p", compile_unit);
+            if (log)
+                log->Printf("compile_unit = %p", compile_unit);
             return;
         }
         
@@ -276,7 +412,8 @@
     
     if (!var_type) 
     {
-        DEBUG_PRINTF("Skipped a definition because it has no type");
+        if (log)
+            log->PutCString("Skipped a definition because it has no type");
         return;
     }
     
@@ -284,7 +421,8 @@
     
     if (!var_opaque_type)
     {
-        DEBUG_PRINTF("Skipped a definition because it has no Clang type");
+        if (log)
+            log->PutCString("Skipped a definition because it has no Clang type");
         return;
     }
     
@@ -294,7 +432,8 @@
     
     if (!type_list)
     {
-        DEBUG_PRINTF("Skipped a definition because the type has no associated type list");
+        if (log)
+            log->PutCString("Skipped a definition because the type has no associated type list");
         return;
     }
     
@@ -302,7 +441,8 @@
     
     if (!exe_ast_ctx)
     {
-        DEBUG_PRINTF("There is no AST context for the current execution context");
+        if (log)
+            log->PutCString("There is no AST context for the current execution context");
         return;
     }
     
@@ -312,11 +452,14 @@
     
     if (!var_location_expr.Evaluate(m_exe_ctx, exe_ast_ctx, NULL, *var_location.get(), &err))
     {
-        DEBUG_PRINTF("Error evaluating location: %s", err.AsCString());
+        if (log)
+            log->Printf("Error evaluating location: %s", err.AsCString());
         return;
     }
     
-    void *copied_type = ClangASTContext::CopyType(context.GetASTContext(), type_list->GetClangASTContext().getASTContext(), var_opaque_type);
+    clang::ASTContext *var_ast_context = type_list->GetClangASTContext().getASTContext();
+    
+    void *copied_type = ClangASTContext::CopyType(context.GetASTContext(), var_ast_context, var_opaque_type);
     
     if (var_location.get()->GetContextType() == Value::eContextTypeInvalid)
         var_location.get()->SetContext(Value::eContextTypeOpaqueClangQualType, copied_type);
@@ -346,12 +489,15 @@
     
     Tuple tuple;
     
-    tuple.m_decl  = var_decl;
-    tuple.m_value = var_location.release();
+    tuple.m_decl        = var_decl;
+    tuple.m_value       = var_location.release();
+    tuple.m_orig_type   = var_opaque_type;
+    tuple.m_ast_context = var_ast_context;
     
     m_tuples.push_back(tuple);
     
-    DEBUG_PRINTF("Found variable");    
+    if (log)
+        log->PutCString("Found variable");    
 }
 
 void
@@ -364,7 +510,8 @@
     
     if (!fun_type) 
     {
-        DEBUG_PRINTF("Skipped a function because it has no type");
+        if (log)
+            log->PutCString("Skipped a function because it has no type");
         return;
     }
     
@@ -372,7 +519,8 @@
     
     if (!fun_opaque_type)
     {
-        DEBUG_PRINTF("Skipped a function because it has no Clang type");
+        if (log)
+            log->PutCString("Skipped a function because it has no Clang type");
         return;
     }
     
@@ -384,16 +532,20 @@
     fun_location->GetScalar() = load_addr;
     
     TypeList *type_list = fun_type->GetTypeList();
-    void *copied_type = ClangASTContext::CopyType(context.GetASTContext(), type_list->GetClangASTContext().getASTContext(), fun_opaque_type);
+    clang::ASTContext *fun_ast_context = type_list->GetClangASTContext().getASTContext();
+    void *copied_type = ClangASTContext::CopyType(context.GetASTContext(), fun_ast_context, fun_opaque_type);
     
     NamedDecl *fun_decl = context.AddFunDecl(copied_type);
     
     Tuple tuple;
     
-    tuple.m_decl  = fun_decl;
-    tuple.m_value = fun_location.release();
+    tuple.m_decl        = fun_decl;
+    tuple.m_value       = fun_location.release();
+    tuple.m_orig_type   = fun_opaque_type;
+    tuple.m_ast_context = fun_ast_context;
     
     m_tuples.push_back(tuple);
     
-    DEBUG_PRINTF("Found function");    
+    if (log)
+        log->PutCString("Found function");    
 }