[Lldb-commits] [lldb] d5b54bb - [lldb] Add support for calling objc_direct methods from LLDB's expression evaluator.

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Tue Dec 17 01:29:07 PST 2019


Author: Raphael Isemann
Date: 2019-12-17T10:28:40+01:00
New Revision: d5b54bbfaf19a8527ebf70fbf23cb8d2937f15ef

URL: https://github.com/llvm/llvm-project/commit/d5b54bbfaf19a8527ebf70fbf23cb8d2937f15ef
DIFF: https://github.com/llvm/llvm-project/commit/d5b54bbfaf19a8527ebf70fbf23cb8d2937f15ef.diff

LOG: [lldb] Add support for calling objc_direct methods from LLDB's expression evaluator.

Summary:
D69991 introduced `__attribute__((objc_direct))` that allows directly calling methods without message passing.
This patch adds support for calling methods with this attribute to LLDB's expression evaluator.

The patch can be summarised in that LLDB just adds the same attribute to our module AST when we find a
method with `__attribute__((objc_direct))` in our debug information.

Reviewers: aprantl, shafik

Reviewed By: shafik

Subscribers: JDevlieghere, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D71196

Added: 
    lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/Makefile
    lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/TestObjCDirectMethods.py
    lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/main.m

Modified: 
    lldb/include/lldb/Symbol/ClangASTContext.h
    lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
    lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
    lldb/source/Symbol/ClangASTContext.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h
index 9537f33b3386..5d228e7bdad7 100644
--- a/lldb/include/lldb/Symbol/ClangASTContext.h
+++ b/lldb/include/lldb/Symbol/ClangASTContext.h
@@ -845,7 +845,7 @@ class ClangASTContext : public TypeSystem {
                         // (lldb::opaque_compiler_type_t type, "-[NString
                         // stringWithCString:]")
       const CompilerType &method_compiler_type, lldb::AccessType access,
-      bool is_artificial, bool is_variadic);
+      bool is_artificial, bool is_variadic, bool is_objc_direct_call);
 
   static bool SetHasExternalStorage(lldb::opaque_compiler_type_t type,
                                     bool has_extern);

diff  --git a/lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/Makefile b/lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/Makefile
new file mode 100644
index 000000000000..afecbf969483
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/Makefile
@@ -0,0 +1,4 @@
+OBJC_SOURCES := main.m
+LD_EXTRAS := -lobjc -framework Foundation
+
+include Makefile.rules

diff  --git a/lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/TestObjCDirectMethods.py b/lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/TestObjCDirectMethods.py
new file mode 100644
index 000000000000..f0152de1ac33
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/TestObjCDirectMethods.py
@@ -0,0 +1,5 @@
+from lldbsuite.test import lldbinline
+from lldbsuite.test import decorators
+
+lldbinline.MakeInlineTest(
+    __file__, globals(), [decorators.skipUnlessDarwin])

diff  --git a/lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/main.m b/lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/main.m
new file mode 100644
index 000000000000..1a199acdda45
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/main.m
@@ -0,0 +1,79 @@
+#import <Foundation/Foundation.h>
+
+int side_effect = 0;
+
+NSString *str = @"some string";
+
+const char *directCallConflictingName() {
+  return "wrong function";
+}
+
+ at interface Foo : NSObject {
+  int instance_var;
+}
+-(int) entryPoint;
+ at end
+
+ at implementation Foo
+-(int) entryPoint
+{
+  // Try calling directly with self. Same as in the main method otherwise.
+  return 0; //%self.expect("expr [self directCallNoArgs]", substrs=["called directCallNoArgs"])
+            //%self.expect("expr [self directCallArgs: 1111]", substrs=["= 2345"])
+            //%self.expect("expr side_effect = 0; [self directCallVoidReturn]; side_effect", substrs=["= 4321"])
+            //%self.expect("expr [self directCallNSStringArg: str]", substrs=['@"some string"'])
+            //%self.expect("expr [self directCallIdArg: (id)str]", substrs=['@"some string appendix"'])
+            //%self.expect("expr [self directCallConflictingName]", substrs=["correct function"])
+}
+
+// Declare several objc_direct functions we can test.
+-(const char *) directCallNoArgs __attribute__((objc_direct))
+{
+  return "called directCallNoArgs";
+}
+
+-(void) directCallVoidReturn __attribute__((objc_direct))
+{
+  side_effect = 4321;
+}
+
+-(int) directCallArgs:(int)i __attribute__((objc_direct))
+{
+  // Use the arg in some way to make sure that gets passed correctly.
+  return i + 1234;
+}
+
+-(NSString *) directCallNSStringArg:(NSString *)str __attribute__((objc_direct))
+{
+  return str;
+}
+
+-(NSString *) directCallIdArg:(id)param __attribute__((objc_direct))
+{
+  return [param stringByAppendingString:@" appendix"];
+}
+
+// We have another function with the same name above. Make sure this doesn't influence
+// what we call.
+-(const char *) directCallConflictingName  __attribute__((objc_direct))
+{
+  return "correct function";
+}
+ at end
+
+int main()
+{
+  Foo *foo = [[Foo alloc] init];
+  [foo directCallNoArgs];
+  [foo directCallArgs: 1];
+  [foo directCallVoidReturn];
+  [foo directCallNSStringArg: str];
+  [foo directCallIdArg: (id)str];
+  [foo entryPoint];  //%self.expect("expr [foo directCallNoArgs]", substrs=["called directCallNoArgs"])
+                     //%self.expect("expr [foo directCallArgs: 1111]", substrs=["= 2345"])
+                     //%self.expect("expr side_effect = 0; [foo directCallVoidReturn]; side_effect", substrs=["= 4321"])
+                     //%self.expect("expr [foo directCallNSStringArg: str]", substrs=['@"some string"'])
+                     //%self.expect("expr [foo directCallIdArg: (id)str]", substrs=['@"some string appendix"'])
+                     //%self.expect("expr [foo directCallConflictingName]", substrs=["correct function"])
+  return 0;
+}

diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 0e16153a2387..bd97c68bff79 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -390,6 +390,10 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
       is_complete_objc_class = form_value.Signed();
       break;
 
+    case DW_AT_APPLE_objc_direct:
+      is_objc_direct_call = true;
+      break;
+
     case DW_AT_APPLE_runtime_class:
       class_language = (LanguageType)form_value.Signed();
       break;
@@ -958,7 +962,8 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
           clang::ObjCMethodDecl *objc_method_decl =
               m_ast.AddMethodToObjCObjectType(
                   class_opaque_type, attrs.name.GetCString(), clang_type,
-                  attrs.accessibility, attrs.is_artificial, is_variadic);
+                  attrs.accessibility, attrs.is_artificial, is_variadic,
+                  attrs.is_objc_direct_call);
           type_handled = objc_method_decl != NULL;
           if (type_handled) {
             LinkDeclContextToDIE(objc_method_decl, die);

diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index c5b630e435e9..4ad757247c3e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -244,6 +244,7 @@ struct ParsedDWARFTypeAttributes {
   bool is_scoped_enum = false;
   bool is_vector = false;
   bool is_virtual = false;
+  bool is_objc_direct_call = false;
   bool exports_symbols = false;
   clang::StorageClass storage = clang::SC_None;
   const char *mangled_name = nullptr;

diff  --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp
index 95bb4551f2c8..3b6b0db34499 100644
--- a/lldb/source/Symbol/ClangASTContext.cpp
+++ b/lldb/source/Symbol/ClangASTContext.cpp
@@ -7769,7 +7769,7 @@ clang::ObjCMethodDecl *ClangASTContext::AddMethodToObjCObjectType(
                       // (lldb::opaque_compiler_type_t type, "-[NString
                       // stringWithCString:]")
     const CompilerType &method_clang_type, lldb::AccessType access,
-    bool is_artificial, bool is_variadic) {
+    bool is_artificial, bool is_variadic, bool is_objc_direct_call) {
   if (!type || !method_clang_type.IsValid())
     return nullptr;
 
@@ -7875,6 +7875,18 @@ clang::ObjCMethodDecl *ClangASTContext::AddMethodToObjCObjectType(
         llvm::ArrayRef<clang::SourceLocation>());
   }
 
+  if (is_objc_direct_call) {
+    // Add a the objc_direct attribute to the declaration we generate that
+    // we generate a direct method call for this ObjCMethodDecl.
+    objc_method_decl->addAttr(
+        clang::ObjCDirectAttr::CreateImplicit(*ast, SourceLocation()));
+    // Usually Sema is creating implicit parameters (e.g., self) when it
+    // parses the method. We don't have a parsing Sema when we build our own
+    // AST here so we manually need to create these implicit parameters to
+    // make the direct call code generation happy.
+    objc_method_decl->createImplicitParams(*ast, class_interface_decl);
+  }
+
   class_interface_decl->addDecl(objc_method_decl);
 
 #ifdef LLDB_CONFIGURATION_DEBUG


        


More information about the lldb-commits mailing list