Skip to content

Commit 7e391ca

Browse files
authored
Merge pull request #652 from jimingham/direct-dispatch-j
Clang added a new feature to the ObjC compiler that will translate me…
2 parents 93bc7d7 + cc83362 commit 7e391ca

File tree

9 files changed

+566
-54
lines changed

9 files changed

+566
-54
lines changed

lldb/include/lldb/Target/ThreadPlan.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,8 +461,12 @@ class ThreadPlan : public std::enable_shared_from_this<ThreadPlan>,
461461
virtual void WillPop();
462462

463463
// This pushes a plan onto the plan stack of the current plan's thread.
464+
// Also sets the plans to private and not master plans. A plan pushed by
465+
// another thread plan is never either of the above.
464466
void PushPlan(lldb::ThreadPlanSP &thread_plan_sp) {
465467
m_thread.PushPlan(thread_plan_sp);
468+
thread_plan_sp->SetPrivate(false);
469+
thread_plan_sp->SetIsMasterPlan(false);
466470
}
467471

468472
ThreadPlanKind GetKind() const { return m_kind; }

lldb/include/lldb/Target/ThreadPlanStepInRange.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ class ThreadPlanStepInRange : public ThreadPlanStepRange,
4949

5050
bool IsVirtualStep() override;
5151

52+
// Plans that are implementing parts of a step in might need to follow the
53+
// behavior of this plan w.r.t. StepThrough. They can get that from here.
54+
static uint32_t GetDefaultFlagsValue() {
55+
return s_default_flag_values;
56+
}
57+
5258
protected:
5359
static bool DefaultShouldStopHereCallback(ThreadPlan *current_plan,
5460
Flags &flags,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
OBJC_SOURCES := stepping-tests.m
2+
LD_EXTRAS := -lobjc -framework Foundation
3+
4+
include Makefile.rules
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"""Test stepping through ObjC method dispatch in various forms."""
2+
3+
from __future__ import print_function
4+
5+
6+
import lldb
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test import lldbutil
10+
11+
12+
class TestObjCDirectDispatchStepping(TestBase):
13+
14+
mydir = TestBase.compute_mydir(__file__)
15+
NO_DEBUG_INFO_TESTCASE = True
16+
17+
def setUp(self):
18+
# Call super's setUp().
19+
TestBase.setUp(self)
20+
# Find the line numbers that we will step to in main:
21+
self.main_source = lldb.SBFileSpec("stepping-tests.m")
22+
23+
@skipUnlessDarwin
24+
@add_test_categories(['pyapi', 'basic_process'])
25+
def test_with_python_api(self):
26+
"""Test stepping through the 'direct dispatch' optimized method calls."""
27+
self.build()
28+
29+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
30+
"Stop here to start stepping",
31+
self.main_source)
32+
stop_bkpt = target.BreakpointCreateBySourceRegex("// Stop Location [0-9]+", self.main_source)
33+
self.assertEqual(stop_bkpt.GetNumLocations(), 15)
34+
35+
# Here we step through all the overridden methods of OverridesALot
36+
# The last continue will get us to the call ot OverridesInit.
37+
for idx in range(2,16):
38+
thread.StepInto()
39+
func_name = thread.GetFrameAtIndex(0).GetFunctionName()
40+
self.assertTrue("OverridesALot" in func_name, "%d'th step did not match name: %s"%(idx, func_name))
41+
stop_threads = lldbutil.continue_to_breakpoint(process, stop_bkpt)
42+
self.assertEqual(len(stop_threads), 1)
43+
self.assertEqual(stop_threads[0], thread)
44+
45+
thread.StepInto()
46+
func_name = thread.GetFrameAtIndex(0).GetFunctionName()
47+
self.assertEqual(func_name, "-[OverridesInit init]", "Stopped in [OverridesInit init]")
48+
49+
50+
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@interface OverridesALot: NSObject
4+
5+
- (void)boring;
6+
7+
@end
8+
9+
@implementation OverridesALot
10+
11+
+ (id)alloc {
12+
NSLog(@"alloc");
13+
return [super alloc];
14+
}
15+
16+
+ (id)allocWithZone: (NSZone *)z {
17+
NSLog(@"allocWithZone:");
18+
return [super allocWithZone: z];
19+
}
20+
21+
+ (id)new {
22+
NSLog(@"new");
23+
return [super new];
24+
}
25+
26+
- (id)init {
27+
NSLog(@"init");
28+
return [super init];
29+
}
30+
31+
- (id)self {
32+
NSLog(@"self");
33+
return [super self];
34+
}
35+
36+
+ (id)class {
37+
NSLog(@"class");
38+
return [super class];
39+
}
40+
41+
- (BOOL)isKindOfClass: (Class)c {
42+
NSLog(@"isKindOfClass:");
43+
return [super isKindOfClass: c];
44+
}
45+
46+
- (BOOL)respondsToSelector: (SEL)s {
47+
NSLog(@"respondsToSelector:");
48+
return [super respondsToSelector: s];
49+
}
50+
51+
- (id)retain {
52+
NSLog(@"retain");
53+
return [super retain];
54+
}
55+
56+
- (oneway void)release {
57+
NSLog(@"release");
58+
[super release];
59+
}
60+
61+
- (id)autorelease {
62+
NSLog(@"autorelease");
63+
return [super autorelease];
64+
}
65+
66+
- (void)boring {
67+
NSLog(@"boring");
68+
}
69+
70+
@end
71+
72+
@interface OverridesInit: NSObject
73+
74+
- (void)boring;
75+
76+
@end
77+
78+
@implementation OverridesInit
79+
80+
- (id)init {
81+
NSLog(@"init");
82+
return [super init];
83+
}
84+
85+
@end
86+
87+
int main() {
88+
id obj;
89+
90+
// First make an object of the class that overrides everything,
91+
// and make sure we step into all the methods:
92+
93+
obj = [OverridesALot alloc]; // Stop here to start stepping
94+
[obj release]; // Stop Location 2
95+
96+
obj = [OverridesALot allocWithZone: NULL]; // Stop Location 3
97+
[obj release]; // Stop Location 4
98+
99+
obj = [OverridesALot new]; // Stop Location 5
100+
[obj release]; // Stop Location 6
101+
102+
obj = [[OverridesALot alloc] init]; // Stop Location 7
103+
[obj self]; // Stop Location 8
104+
[obj isKindOfClass: [OverridesALot class]]; // Stop Location 9
105+
[obj respondsToSelector: @selector(hello)]; // Stop Location 10
106+
[obj retain]; // Stop Location 11
107+
[obj autorelease]; // Stop Location 12
108+
[obj boring]; // Stop Location 13
109+
[obj release]; // Stop Location 14
110+
111+
// Now try a class that only overrides init but not alloc, to make
112+
// sure we get into the second method in a combined call:
113+
114+
obj = [[OverridesInit alloc] init]; // Stop Location 15
115+
116+
return 0; // Stop Location 15
117+
}

0 commit comments

Comments
 (0)