-
Notifications
You must be signed in to change notification settings - Fork 805
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement NSProxy #2499
Implement NSProxy #2499
Conversation
Frameworks/Foundation/NSProxy.mm
Outdated
@Notes | ||
*/ | ||
- (void)forwardInvocation:(NSInvocation*)anInvocation { | ||
UNIMPLEMENTED(); | ||
[NSException raise:NSInvalidArgumentException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should these just be NSInvalidAbstractInvocationReturn() ? I know it's not a class cluster per se, but it's still "Ya gotta override this"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, documented NSInvalidArgumentException: https://developer.apple.com/reference/foundation/nsproxy/1416417-forwardinvocation?language=objc
intptr_t* refCount = ((intptr_t*)self) - 1; | ||
// We allow refcounts to run into the negative, but should only | ||
// deallocate once. | ||
if (__sync_sub_and_fetch(refCount, 1) == -1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be <= ? Ideally we'd never go below -1 but in case we ever should due to async nonsense we wouldn't want to leak
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- this is just lifted from NSObject.mm
- async nonsense wouldn't be able to cause that since __sync_sub_and_fetch is atomic
Frameworks/Foundation/NSObject.mm
Outdated
@@ -708,7 +707,8 @@ void WinObjC_SetMissingSelectorFatal(BOOL fatal) { | |||
} | |||
@end | |||
|
|||
static void _dealloc_zombify(id self, SEL _cmd); // forward declaration | |||
static void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I'd prefer not having the format changes in this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'll fix this one and leave the rest, if that's ok
@@ -737,7 +737,7 @@ + (BOOL)isSubclassOfClass:(Class)classRef { | |||
/** | |||
@Status Interoperable | |||
*/ | |||
- (void)doesNotRecognizeSelector: (SEL)selector { | |||
- (void)doesNotRecognizeSelector:(SEL)selector { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then again, some of them are good ..
Frameworks/Foundation/NSProxy.mm
Outdated
@Notes | ||
*/ | ||
- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector { | ||
UNIMPLEMENTED(); | ||
return StubReturn(); | ||
[NSException raise:NSInvalidArgumentException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: macro these, and use %hs
+ __PRETTY_FUNCTION__
to get the method name in the macro
@Status Interoperable | ||
@Notes | ||
*/ | ||
- (Class)superclass { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure on whether this should be calling [self class]
; thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also the same as NSObject.mm... going to propose we leave both for the moment and let sleeping beasts lie.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed my mind and got curious how the reference platform behaved and it appears superclass is polymorphic so I will make this change in both places,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May want to do the fix for NSObject in a separate PR. Doubt it would cause any regressions but it's foundational enough that it might and should be thoroughly tested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mm, my thought is that if a change like that breaks something, we'll either be able to catch it in CI build, or it's so incredibly subtle despite being in such an exercised class that doing it in a separate change won't really gain us anything, so I'll elect to risk it. (I will probably regret saying this a week from now)
Frameworks/Foundation/NSProxy.mm
Outdated
@Notes | ||
*/ | ||
- (instancetype)self { | ||
UNIMPLEMENTED(); | ||
return StubReturn(); | ||
return (id)self; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: cast necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems not
@Notes | ||
*/ | ||
- (BOOL)isKindOfClass:(Class)aClass { | ||
UNIMPLEMENTED(); | ||
return StubReturn(); | ||
Class forwardClass = static_cast<Class>([self performSelector:@selector(class)]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aaa is it really guaranteed that it calls forwardInvocation:
for class
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not sure I like that this is different from calling class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's the contract unfortunately :( [NSProxy class] does not return a forwarded class
@Notes | ||
*/ | ||
- (id)performSelector:(SEL)aSelector withObject:(id)anObject { | ||
UNIMPLEMENTED(); | ||
return StubReturn(); | ||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:aSelector]]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's strange to me that these go through invocation instead of hitting the invocation-forwarding path
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like performSelector:
and friends could just call objc_msgSend; that would go through the invocation forwarding and capture codepath
It's less verbose, but perhaps there is an advantage to creating the invocation directly!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
discussed offline, leaving as is
} | ||
|
||
@end | ||
@end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you may have to implement doesNotRecognizeSelector:, and call it from the default forwardInvocation: implementation just like NSObject -- that's how people will get missing selector exceptions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already tested for in the unit test - I believe it forwards to the remote doesNotRecognizeSelector.
+ (id)alloc; | ||
+ (id)allocWithZone:(NSZone*)zone; | ||
- (void)dealloc; | ||
- (void)finalize; | ||
- (void)forwardInvocation:(NSInvocation*)anInvocation; | ||
- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector; | ||
+ (BOOL)respondsToSelector:(SEL)aSelector; | ||
+ (Class) class; | ||
+ (Class)class; | ||
+ (Class)superclass; // Not in doc, but is supported |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't the NSObject protocol contain this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it does not!
@implementation _NSTestMutableArrayProxy | ||
|
||
- (instancetype)initWithMutableArray:(NSMutableArray*)array { | ||
self->_forwardArray = array; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: document not calling super init
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't/shouldn't call super init on NSProxy - it's NS_UNAVAILABLE (this matches the reference platform)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! It'd be good to have a comment in here so somebody doesn't think it's broken.
Our CC (or that one really didactic talk I gave) states that we should almost never not call init. Since this is one of the cases where we mustn't, it deserves callout!
…olymorphic with respect to [self class] - Changed both [NSObject self] and [NSProxy self] to no longer do a cast - Misc CR feedback
Could not repro CI build failure locally, queuing again. |
Fixes #2348