Index: lldb/include/lldb/Symbol/ClangASTContext.h =================================================================== --- lldb/include/lldb/Symbol/ClangASTContext.h +++ lldb/include/lldb/Symbol/ClangASTContext.h @@ -825,7 +825,7 @@ // (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); Index: lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/Makefile =================================================================== --- /dev/null +++ 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 Index: lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/TestObjCDirectMethods.py =================================================================== --- /dev/null +++ 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]) Index: lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/main.m =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/lang/objc/objc_direct-methods/main.m @@ -0,0 +1,79 @@ +#import + +int side_effect = 0; + +NSString *str = @"some string"; + +const char *directCallConflictingName() { + return "wrong function"; +} + +@interface Foo : NSObject { + int instance_var; +} +-(int) entryPoint; +@end + +@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"; +} +@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; +} Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -244,6 +244,7 @@ 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; Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -390,6 +390,10 @@ 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; @@ -954,7 +958,8 @@ 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); Index: lldb/source/Symbol/ClangASTContext.cpp =================================================================== --- lldb/source/Symbol/ClangASTContext.cpp +++ lldb/source/Symbol/ClangASTContext.cpp @@ -8485,7 +8485,7 @@ // (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; @@ -8591,6 +8591,18 @@ llvm::ArrayRef()); } + 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