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

Investigate further Encodings #68

Closed
madsmtm opened this issue Nov 3, 2021 · 6 comments · Fixed by #412
Closed

Investigate further Encodings #68

madsmtm opened this issue Nov 3, 2021 · 6 comments · Fixed by #412
Labels
A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates enhancement New feature or request

Comments

@madsmtm
Copy link
Owner

madsmtm commented Nov 3, 2021

There are a few encodings we don't yet support (Vector?), and we don't support type specifiers / qualifiers (_Atomic, const, ...) either.

See #20.

Also, does objc2-encode require knowledge of the compiler and runtime? E.g. it is often allowed to omit details like in, inout, oneway and so on, but does this change significantly across compilers and/or runtimes?

@madsmtm madsmtm added the enhancement New feature or request label Nov 3, 2021
@madsmtm
Copy link
Owner Author

madsmtm commented Nov 3, 2021

Apple's objc4 defines (using GNUStep's ordering and grouping):

#define _C_ID       '@'
#define _C_CLASS    '#'
#define _C_SEL      ':'
#define _C_BOOL     'B'

#define _C_CHR      'c'
#define _C_UCHR     'C'
#define _C_SHT      's'
#define _C_USHT     'S'
#define _C_INT      'i'
#define _C_UINT     'I'
#define _C_LNG      'l'
#define _C_ULNG     'L'
#define _C_LNG_LNG  'q'
#define _C_ULNG_LNG 'Q'

#define _C_FLT      'f'
#define _C_DBL      'd'

#define _C_BFLD     'b'
#define _C_VOID     'v'
#define _C_UNDEF    '?'
#define _C_PTR      '^'

#define _C_CHARPTR  '*'
#define _C_ATOM     '%'

#define _C_ARY_B    '['
#define _C_ARY_E    ']'
#define _C_UNION_B  '('
#define _C_UNION_E  ')'
#define _C_STRUCT_B '{'
#define _C_STRUCT_E '}'
#define _C_VECTOR   '!'

#define _C_CONST    'r'

GNUStep's libobjc2 additionally defines:

#define _C_COMPLEX  'j'
#define _C_IN       'n'
#define _C_INOUT    'N'
#define _C_OUT      'o'
#define _C_BYCOPY   'O'
#define _C_ONEWAY   'V'

And GCC's libobjc furthermore define:

#define _C_BYREF        'R'
#define _C_GCINVISIBLE  '|'

GCC's notes on _C_ATOM:

_C_ATOM is never generated by the compiler. You can treat it as equivalent to "*".

@madsmtm

This comment has been minimized.

@madsmtm
Copy link
Owner Author

madsmtm commented Nov 26, 2021

Just found that the following methods:

  • method_getNumberOfArguments
  • method_getReturnType
  • method_copyReturnType
  • method_getArgumentType
  • method_copyArgumentType

All fail in counting properly in Apple's runtime (though GNU's does this fine, and I would guess GNUStep's as well) when using _Complex and _Atomic types. The issue in their runtime lies here, they forgot to include case 'j': and case 'A':.

For example, the following produces wrong results:

#import <objc/runtime.h>
#import <Foundation/Foundation.h>

@interface TestObject : NSObject
- (_Complex float)myMethod;
@end

@implementation TestObject
- (_Complex float)myMethod {
    return 0.0;
}
@end

int main (int argc, const char * argv[]) {
    Method m = class_getInstanceMethod([TestObject class], @selector(myMethod));

    NSLog(@"Encoding %s", method_getTypeEncoding(m));

    NSLog(@"Return %s", method_copyReturnType(m));
    NSLog(@"Argument count %i", method_getNumberOfArguments(m));
    NSLog(@"self %s", method_copyArgumentType(m, 0));
    NSLog(@"_cmd %s", method_copyArgumentType(m, 1));
    NSLog(@"Arg #1 %s", method_copyArgumentType(m, 2));

    return 0;
}

Outputs:

Encoding jf16@0:8
Return j
Argument count 3
self f
_cmd @
Arg #1 :

Vs. the expected:

Encoding jf16@0:8
Return jf
Argument count 2
self @
_cmd :
Arg #1 (null)

In effect, this means that method_getTypeEncoding is the only reliable way to get this information, provided we want to support complex types. Luckily, this is probably what we're going to do in the future anyhow, since it doesn't allocate, it doesn't scan the entire string to find the amount of arguments, it doesn't copy, and we can always just grab a smaller slice of it on the Rust side if we need to!

Also, method_getReturnType is broken in GNU's runtime and returns the stack offsets as well, so making our own implementation of these broken methods sounds preferable.

@madsmtm
Copy link
Owner Author

madsmtm commented Nov 29, 2021

I tried adding Encoding::Const (corresponding to the 'r' code), and then changed the following implementations:

unsafe impl<T: RefEncode + ?Sized> Encode for *const T {
    const ENCODING: Encoding<'static> = Encoding::Const(&T::ENCODING_REF);
}
unsafe impl<'a, T: RefEncode + ?Sized> Encode for &'a T {
    const ENCODING: Encoding<'static> = Encoding::Const(&T::ENCODING_REF);
}
unsafe impl<'a, T: RefEncode + ?Sized> Encode for Option<&'a T> {
    const ENCODING: Encoding<'static> = Encoding::Const(&T::ENCODING_REF);
}

But this doesn't really help with debugging:

  • There are lots of places in the Objective-C definitions where the pointers could be marked const, but aren't
  • Sometimes we can on the Rust-side guarantee that the pointer is immutable, even though the Objective-C side can't

In short, users would have to coerce their references to *const or *mut pointers to make it match what Objective-C does, even though it is often wrong. So yeah, that idea goes out the window!

Encoding::Atomic and such might still be interesting?

@madsmtm
Copy link
Owner Author

madsmtm commented Apr 2, 2022

Also: Bitfields are encoded differently on GNUStep (future compatibility hazard avoided in #138). To achieve perfect compatibility, we would need a gnustep feature flag on objc2-encode - luckily this can be added later on!

@madsmtm madsmtm removed this from the objc2 v0.3 milestone Apr 2, 2022
@madsmtm madsmtm added the A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates label Jan 27, 2023
@madsmtm
Copy link
Owner Author

madsmtm commented Jan 29, 2023

#412 resolves the bitfield problems, and moves the remaining items in here (if any) into TODO's in the code (since they're mostly theoretical improvements, and not really something of much use)

@madsmtm madsmtm closed this as completed Jan 29, 2023
@madsmtm madsmtm linked a pull request Jan 29, 2023 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant