How to deduce from NSMethodSignature that a struct argument is passed by pointer?

How to deduce from NSMethodSignature that a struct argument is passed by pointer?

Specifically on ARM.

For example if I have:

@protocol TestProtocol <NSObject>
- (void)time:(CMTime)time;
- (void)rect:(CGRect)point;
@end

And then I do:

  struct objc_method_description methodDescription1 =
    protocol_getMethodDescription(@protocol(TestProtocol), @selector(time:), YES, YES);
  struct objc_method_description methodDescription2 =
    protocol_getMethodDescription(@protocol(TestProtocol), @selector(rect:), YES, YES);

  NSMethodSignature *sig1 = [NSMethodSignature signatureWithObjCTypes:methodDescription1.types];
  NSMethodSignature *sig2 = [NSMethodSignature signatureWithObjCTypes:methodDescription2.types];

  const char *arg1 = [sig1 getArgumentTypeAtIndex:2];
  const char *arg2 = [sig2 getArgumentTypeAtIndex:2];

  NSLog(@"%s %s", methodDescription1.types, arg1);
  NSLog(@"%s %s", methodDescription2.types, arg2);

The output is:

v40@0:8{?=qiIq}16 {?=qiIq}
v48@0:8{CGRect={CGPoint=dd}{CGSize=dd}}16 {CGRect={CGPoint=dd}{CGSize=dd}}

Both look similar, no indication that CMTime will be actually passed as a pointer.

But when I print the debug description:

  NSLog(@"%@", [sig1 debugDescription]);
  NSLog(@"%@", [sig2 debugDescription]);

The first prints:

  ...
  argument 2: -------- -------- -------- --------
        type encoding (^) '^{?=qiIq}'
        flags {isPointer}
  ...

While the second prints:

  ...
  argument 2: -------- -------- -------- --------
        type encoding ({) '{CGRect={CGPoint=dd}{CGSize=dd}}'
        flags {isStruct}
  ...

So this information is indeed stored in the method signature, but how do I retrieve it without parsing the debug description?

Are there rules I can use to deduce this myself? I tried to experiment with different structs but it is hard to spot a pattern.

Are there rules I can use to deduce this myself?

I think this is fallout from the standard Arm calling conventions. Writing ARM64 Code for Apple Platforms has a pointer to the Arm doc for this (my references are from ARM IHI 0055B, which I just downloaded). Section 4.3.5.1 of that doc defines the term Homogeneous Floating-point Aggregate (HFA). If I’m reading this correctly, a CGRect qualifies as an HFA, and thus it’s passed in registers per 5.4.2.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I still curious if I can get this info from the runtime without the need to implement these rules myself.

I couldn’t find a way to get that info via the NSMethodSignature public API. The debugDescription property is dumping internal state and not all of that internal state is accessible via the public API [1].

Why do you need this info?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Curiously, while rummaging around in the code I stumbled across various Arm-specific internal routines with HFA in the name.

I want to fix this by …

I don’t think you’re going to be able to do that without architecture-specific code. The point of NSInvocation is that it’s supposed to isolate you from this architecture-specific stuff. However, NSInvocation is very much a black box. It does what it does well, but if that doesn’t meet your needs, and so you need to look inside the box, it doesn’t provide any infrastructure for helping with the architecture-specific stuff.

Instead of retaining it's arguments with the -retainArguments they decided to implement their own retaining method

Do you know why?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

How to deduce from NSMethodSignature that a struct argument is passed by pointer?
 
 
Q