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

Improve Objective-C support #4777

Open
wants to merge 67 commits into
base: master
Choose a base branch
from

Conversation

LunaTheFoxgirl
Copy link
Contributor

@LunaTheFoxgirl LunaTheFoxgirl commented Nov 12, 2024

This pull-request aims to improve the Objective-C support of LDC. This PR additionally changes the Objective-C generation system to only support the Objective-C 2.0 ABI, as very little documentation of older ABIs have survived.

A good chunk of this code is more or less taken from the OpenD implementation, but I'm already working on cleaning parts up as I go. I am looking into how feasible it'll be to make extern(Objective-C) classes export neccesary ABI for Objective-C code to be able to call it as well, which mainly involves metadata generation.

TODO List:

  • Classes
    • ClassRO Tables
    • Class List Tables
    • Swift Stub Class Tables (@swift keyword)
    • Dynamic Class Casting
  • Methods
    • Method List Tables
    • Selector Reference Tables
  • Protocols
    • Protocol List Table
    • Dynamic Protocol Casting
  • Instance Variables
    • Generate instance variables and offsets

gen/abi/x86-64.cpp Outdated Show resolved Hide resolved
gen/objcgen.cpp Outdated Show resolved Hide resolved
@LunaTheFoxgirl
Copy link
Contributor Author

Question: in this implementation I wish to add another UDA to ldc.attributes called @swift.

Idea there is to implement support for binding Swift interop class stubs as well, which have unique behaviour that would require this new attribute.

Essentially Swift may declare Objective-C classes in the __objc_stubs section with an isa field pointing to address 0x1. Followed by a function pointer that would need to be invoked to instantiate the class definition, via the objc_loadClassRef helper function.

This would allow interop with Swift code using bridging headers and wouldn't be too much extra work.

Is it okay if I add that to this PR?

@thewilsonator
Copy link
Contributor

Is it okay if I add that to this PR?

Yes.

@adamdruppe
Copy link
Contributor

I am looking into how feasible it'll be to make extern(Objective-C) classes export neccesary ABI for Objective-C code to be able to call it as well, which mainly involves metadata generation.

this already works in opend so if you copy the impl it should work here too; that's how the final iphone demo from my blog worked, as well as simpledisplay's cocoa implementation, and to triple check i just did one more test:

@interface Thing : NSObject
   - (void) test
@end 

int main() {
  [[[Thing alloc] init] test];
}

and then the D

extern(Objective-C)
class Thing : NSObject {
  void test() @selector("test") {
        printf("here\n");
   }
}

and all worked.

of course, possible i missed some details that won't emerge until you get into more features, but still a lot already works in the opend world.

@adamdruppe
Copy link
Contributor

BTW something i think would be kinda cool is a kind of import objective-c

dstep can do a good amount of that already, and the objective c parts look easier to parse and interface with than regular import c

so im p sure it doable with a week or two of work

@LunaTheFoxgirl
Copy link
Contributor Author

BTW something i think would be kinda cool is a kind of import objective-c

dstep can do a good amount of that already, and the objective c parts look easier to parse and interface with than regular import c

so im p sure it doable with a week or two of work

Yeah, I'm thinking of making an Objective-C code generator once I get the compiler support up and running.
Got protocols working now, might implement categories as well. Next up is codegen for swift stub classes.

@thewilsonator
Copy link
Contributor

(once this is good to go) Could you please open a PR to DMD with all of the frontend/druntime changes? (Just stub out anything needs anything extra to work)

@LunaTheFoxgirl
Copy link
Contributor Author

(once this is good to go) Could you please open a PR to DMD with all of the frontend/druntime changes? (Just stub out anything needs anything extra to work)

Sure, will do. However I think I'll reduce the scope of this PR slightly to just be the core objective-c and Swift stub class support. Given that some existing Apple platforms don't align neatly with the code I was referencing I'm doing a pretty big refactor of the objective-c data struct generation to be compatible with all of the Apple sub architectures supported.

@LunaTheFoxgirl
Copy link
Contributor Author

cc @adamdruppe once I finish this PR you may want to back integrate it into OpenD's LDC fork. Your current implementation is broken on quite a few platforms and in some cases may crash the Xcode linker

@adamdruppe
Copy link
Contributor

plz write up some notes as you go, as it might also apply back to dmd's separate implementation (and the abi spec on the website) as well. depends on if it was just me bugging it up or if the original was wrong too.

much of it came from reverse engineering the output on a x86 Mac so no surprise they'd be some differences (one we all found early is the arm objc_msgSend is slightly different on arm), then i just sucked at ldc code so prolly a lot of impl bugs too lol.

@LunaTheFoxgirl
Copy link
Contributor Author

plz write up some notes as you go, as it might also apply back to dmd's separate implementation (and the abi spec on the website) as well. depends on if it was just me bugging it up or if the original was wrong too.

much of it came from reverse engineering the output on a x86 Mac so no surprise they'd be some differences (one we all found early is the arm objc_msgSend is slightly different on arm), then i just sucked at ldc code so prolly a lot of impl bugs too lol.

Yeah my recommendation there is to look at the actual objective-c runtime source. The data structures relevant are listed there https://github.com/apple-oss-distributions/objc4 as well as the Swift interop documentation.

I'm adding the finishing touches to this PR tonight, and will mark it as ready to merge then.

@LunaTheFoxgirl LunaTheFoxgirl marked this pull request as ready for review November 22, 2024 05:32
@kinke
Copy link
Member

kinke commented Nov 27, 2024

Nice work, thanks for tackling this! Just a superficial review from my side; I have 0 interest in Apple specifics and don't wanna get into its details myself.

@LunaTheFoxgirl
Copy link
Contributor Author

LunaTheFoxgirl commented Nov 28, 2024

Nice work, thanks for tackling this! Just a superficial review from my side; I have 0 interest in Apple specifics and don't wanna get into its details myself.

Yeah, I kind of have to get into the specifics myself due to my business needing it. Initially just used cursed compile time shenanigans to get things working but I ended up realising that in some ways to get my product onto the App Store for iPad and a second product to iPhones I need to have proper support in LDC.

I plan to make further PRs in the future to improve the state of objective-c (and Swift) support to LDC and possibly DMD.

@kinke
Copy link
Member

kinke commented Nov 28, 2024

There are at least 2 Objective-C tests from upstream that are still disabled for LDC: compilable/objc_{class,interface_final_19654}.d. I guess just an oversight? (I've just grepped the dmd-testsuite CI log for objc.)

@LunaTheFoxgirl
Copy link
Contributor Author

There are at least 2 Objective-C tests from upstream that are still disabled for LDC

yup, just an oversight on my part, there we go.

@LunaTheFoxgirl
Copy link
Contributor Author

LunaTheFoxgirl commented Nov 28, 2024

@kinke okay, those tests have been added and they pass now, also added selector auto-gen for property functions like specified in the DIP.

That being said, this selector gen should be implemented upstream properly down the line. Will look into making a patch to DMD later, then phasing out my little hack there.

@jacob-carlborg
Copy link
Contributor

also added selector auto-gen for property functions like specified in the DIP.

That's not implemented in upstream IIRC.

Try to upstream as much as possible when implementing new features.

@LunaTheFoxgirl
Copy link
Contributor Author

LunaTheFoxgirl commented Nov 28, 2024

I will, currently doing some refactoring to make the code easier to follow.
After this is merged, I'll look into making a PR for upstream.

That being said, DMD is practically useless for apple device development given that it's arm support is not completed, and I have limited time to spend on this. I really need to get back to work on my products.

@LunaTheFoxgirl
Copy link
Contributor Author

@adamdruppe I've refactored the code to be less messy, hopefully it's easier to follow now?

@adamdruppe
Copy link
Contributor

I'll reread the whole thing when I get another chunk of time free, idk if it'll be today or tomorrow, but I'll let you know when I do.

My biggest concern is just if it works and that last test I did with it passing was a good sign!

@LunaTheFoxgirl
Copy link
Contributor Author

@kinke anything left to solve? All the tests succeed (minus the ones that are either broken for unrelated reasons and the ones where you've run out of compute credits)

@LunaTheFoxgirl
Copy link
Contributor Author

Also it seems my refactor somehow fixed all the random asserts that was happening.

dmd/objc.d Show resolved Hide resolved
dmd/objc.h Show resolved Hide resolved
@LunaTheFoxgirl
Copy link
Contributor Author

I think that's everything?
Sorry if I'm a bit pushy, I've been working unholy hours on this the past few days. I'm very exhausted ^^;

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.

6 participants