Skip to content
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

Merged
merged 2 commits into from
Apr 13, 2017
Merged

Implement NSProxy #2499

merged 2 commits into from
Apr 13, 2017

Conversation

ms-jihua
Copy link
Contributor

Fixes #2348

@Notes
*/
- (void)forwardInvocation:(NSInvocation*)anInvocation {
UNIMPLEMENTED();
[NSException raise:NSInvalidArgumentException
Copy link
Contributor

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"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Contributor

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

Copy link
Contributor Author

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

@@ -708,7 +707,8 @@ void WinObjC_SetMissingSelectorFatal(BOOL fatal) {
}
@end

static void _dealloc_zombify(id self, SEL _cmd); // forward declaration
static void

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

Copy link
Contributor Author

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 {

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 ..

@Notes
*/
- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector {
UNIMPLEMENTED();
return StubReturn();
[NSException raise:NSInvalidArgumentException

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 {

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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,

Copy link
Contributor

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.

Copy link
Contributor Author

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)

@Notes
*/
- (instancetype)self {
UNIMPLEMENTED();
return StubReturn();
return (id)self;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: cast necessary?

Copy link
Contributor Author

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)]);

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?

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

Copy link
Contributor Author

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]];

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean?

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!

Copy link
Contributor Author

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

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

Copy link
Contributor Author

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

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?

Copy link
Contributor Author

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;

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

Copy link
Contributor Author

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)

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
@ms-jihua
Copy link
Contributor Author

Could not repro CI build failure locally, queuing again.

@ms-jihua ms-jihua merged commit 2da953b into microsoft:develop Apr 13, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants