-
-
Notifications
You must be signed in to change notification settings - Fork 608
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 basic support for Objective-C methods. #4321
Implement basic support for Objective-C methods. #4321
Conversation
c08211f
to
fc5605e
Compare
| stringtable->_init(); | ||
|
|
||
| return stringtable; | ||
| } |
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 can remove this function and call StringTable::reset(..) instead, which does the same thing.
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 I don't have to new the string table?
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.
Yes, AFAIU. The default constructor doesn't do anything.
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.
Ok, cool, I'll update that.
|
I think the autotester is currently failing on Windows, because you need to include |
| @@ -353,6 +354,9 @@ Msgtable msgtable[] = | |||
| { "basic_ostream" }, | |||
| { "basic_iostream" }, | |||
| { "char_traits" }, | |||
|
|
|||
| // Compiler recognized UDA's | |||
| { "udaSelector", "core.attribute.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.
Would it be better not to detect the special UDA by name, but have the user import e.g. core.objc, which contains a symbol selector, and let the compiler detect this special symbol? Then it wouldn't make existing @selector UDAs invalid, at the cost of needing an explicit import.
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.
That is how it works. See https://github.com/jacob-carlborg/dmd/blob/dobjc_instance_methods/src/objc_func_selector.c#L48
Ok, I see. I'll add it to win32.mak. |
| StringExp *se = (*literal->elements)[0]->toStringExp(); | ||
| assert(se); | ||
|
|
||
| self->objc.selector = ObjcSelector::lookup((const char *)se->toUTF8(sc)->string); |
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.
ObjcSelector::lookup(..) is a stub, so you are just delaying the error, afaics.
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.
Yes, that's a problem.
83912cf
to
09b3980
Compare
|
@ZombineDev a couple of updates:
I couldn't use @WalterBright @yebblies @9rnsr please review. |
|
There are some parts of this that don't match the usual dmd style - eg ref parameters, the style of asserts, calling parameters There also seem to be a lot of small new files. Is this because later pull requests are going to flesh them out a lot more? Is |
| StructLiteralExp *literal = (StructLiteralExp *)e; | ||
| assert(literal->sd); | ||
|
|
||
| if (strcmp(Id::udaSelector->string, literal->sd->toPrettyChars()) == 0) |
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.
if(Id::udaSelector == literal->sd->ident) ?
The whole point of Id is to avoid doing string comparisons.
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 need the fully qualified name. literal->sd->ident->string will only contain "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.
Just throwing something random out there.
Maybe have Id::udaSelector be = "selector" and then:
if (literal->sd->ident == Id::udaSelector
&& (mod = literal->sd->parent->isModule()) != NULL
&& mod->md->packages.dim == 2
&& (*mod->md->packages)[0].ident == Id::Pool("core")
&& (*mod->md->packages)[1].ident == Id::Pool("attribute"))
{
...
}
Will have to double check if that is even possible (the Package may only hold the string, not the Identifier)
I know it is a mouthful, but should be faster than toPrettyChars and have the bonus of not wasting memory.
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.
Hehe, that is a lot of comparisons. @yebblies what do you think?
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.
@jacob-carlborg - there could always be a new boolean method isCoreAttributeModule() or something of the sort.
Would shorten it down to:
&& (mod = literal->sd->parent->isModule()) != NULL
&& mod->isCoreAttributeModule())
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.
Another option is to move this matching code to StructDeclaration::StructDeclaration, and store a reference in a static variable as is done for moduleinfo. (and lots of similar stuff for ClassDeclaration). This has the benefit of completely avoiding the check when core.attribute isn't imported.
If you did create a isCoreModule("attribute") it could be reused in other places, like detecting intrinsics.
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 can do that. Wouldn't isCoreModule require doing a string comparison since the module name would be an argument?
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.
Yeah, isCoreModule(Id::attribute) would be better.
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 could still use Id::Pool(str) on the string for pointer comparisons - but yes, having the idents pre-cached and ready helps too.
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 could still use Id::Pool(str) on the string for pointer comparisons
Well not really, because Identifier::idPool would have to do a string comparison.
All functions prefixed with The reason for the ref parameters is that I wanted to avoid parameters with two pointers. But perhaps that's preferred. I also think it clearly shows which parameters will be modified. Also, this code was original inlined in some other method, using references required far less changes when it was moved to free functions. I'm not sure that you mean with the asserts. How should I/should I not use them?
Yes. Also, one of the GDC developers asked me to separate out the front end code from the glue code. For every (most)
Hmm. |
|
@jacob-carlborg Is |
Yes, but including the name of the caller in the function is not super useful.
There is a huge amount of code already in dmd that has been moved out of member functions (eg into visitors) and none of it uses
There is no need to avoid parameters with two pointers. Another option is to return the modified
Current code uses
Keeping the frontend/glue stuff split is important, but maintaining a 1-1 mapping from objc_ files to the original is not. If some of the files can be logically combined they should be, within reason. eg
Another option is using |
It's kind of hard to come up with names for all these small functions. The final version will have 93 of these free functions.
Ok.
Ok, I'll change to two pointers. Other functions will modify multiple parameters, so for those it won't work. If I mix the styles I'm pretty certain someone will complain about that.
I can change that. I'm not sure what issue 4733 has to do with this, or are you thinking about ddmd?
Could you please tell how I should organize the code, it would be much easier then me guessing. The total line count of all
I'm just explaining why the code looks like it does.
Seems like it's not used anymore. I don't even know if that validation is necessary. |
| @@ -534,6 +535,7 @@ class FuncDeclaration : public Declaration | |||
| // scopes from having the same name | |||
| VarDeclaration *vthis; // 'this' parameter (member and nested) | |||
| VarDeclaration *v_arguments; // '_arguments' parameter | |||
| Ojbc_FuncDeclaration objc; | |||
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.
Ojbc_FuncDeclaration looks like a typo (should it be Objc_FuncDeclaration?)
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.
Is the 'n' unicode or something?
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.
No, Ojbc vs Objc.
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.
Why didn't the 'n' show up in the email? Weird.
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.
Yes, it's a typo.
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.
Nearly ready, I'll probably make a PR tomorrow. I'm just not really happy with the overhead of introducing a new type.
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 let the testing with gdc do the talking. :)
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.
Has that branch anything to do with my pull request? Or are you just taking any opportunity to communicate 😃
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.
No comment. :P
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.
Nothing to do with the pull request, sorry.
Yes, issue 4733 + ddmd. |
Validating the number of colons isn't technically necessary, but it's a cheap way to catch some typos at compile time instead of at runtime. Think what would happen declaring |
Right, then it's all good 😃, |
|
@yebblies about the file structure, how about this: one file for the glue code, one for the stubs and one for the rest? |
That sounds better. 4000 lines of code isn't actually that much compared to some of dmd's files. |
0313f74
to
21f9f7b
Compare
|
Anyone know how I should modify the windows makefile to make the test pass? @yebblies is this related to magicport? |
|
Yes, you might need to add any new types to the lists or make sure that the new header/source files are scanned. http://wiki.dlang.org/Updating_Pull_Requests_for_DDMD |
|
So, any plans to make all those horrid flat functions first class citizens? |
21f9f7b
to
25ad571
Compare
|
@yebblies Could you please verify this commit: jacob-carlborg@a003913. It's the changes I needed to make to make magicport work. BTW, doesn't the auto tester run magicport by default on Posix systems? |
|
The The auto tester runs magicport and builds ddmd on all platforms. |
Before that change I got this error: It failed to rewrite the call to the super constructor. It looks like this: this.Declaration = id;
Yeah, I completely missed that.
It doesn't look like it does. It passes on all platforms expect for Windows, and I haven't made any changes to make it work for magicport (that are pushed). Also, when explicitly run the "ddmd" make target locally I got errors that didn't show up in the auto tester. |
|
@yebblies Now I noticed that this doesn't work either. I need the default constructor in C++ after I moved the initialization of I don't think magicport supports initializing variables in the initialization list for a constructor, because DMD never uses that, until now. Before this, DMD always used pointers to all classes. |
|
Magicport does support both super calls and member initialization in the ctor init list, unless this is a weird corner case I missed. Other classes in DMD do use this. Aaaaaand it looks like it only supports the 'super' re-write if there is only one expression in the init list, so that explains that. The code is in dprinter.d:253 if you feel like adding support for both together. It looks like the posix ddmd build was stopped at some point due to makefile changes. Hopefully it still builds. You can have a struct with a default ctor, but you will need to make sure that the default init D generates is valid (all members must be initialized to T.init, ctor does no real processing etc) and add it to the |
25ad571
to
6e217bc
Compare
At least it builds for me locally. |
| @@ -1193,6 +1194,7 @@ Language changes listed by -transition=id:\n\ | |||
| VersionCondition::addPredefinedGlobalIdent("D_NoBoundsChecks"); | |||
|
|
|||
| VersionCondition::addPredefinedGlobalIdent("D_HardFloat"); | |||
| objc_tryMain_dObjc(); | |||
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 is tryMain and why must I be forced to call this if I wish to merge support into GDC?
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.
That objc_tryMain_dObjc function just adds a predefined version identifier in case you want to use version (D_ObjectiveC) to detect whether Objective-C features are available at compile-time. (If your backend does not support emitting Objective-C code, then you probably shouldn't add the 'D_ObjectiveC' version identifier.)
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.
For me it's not a question of whether or not GCC supports, it's a question of why you are poisoning my glue interface with names like 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.
Jacob did this after Walter asked for Objective-C related things to be put in separate functions. Personally, I find it more confusing than useful. Those functions could have more meaning full names I guess, but all those parts weren't originally meant to be standalone functions in the first place.
If it was only me, I'd just call VersionCondition::addPredefinedGlobalIdent("D_ObjectiveC") here and delete objc_tryMain_dObjc (it was like this in the original). But with the only advice from Walter being that things must be kept segregated in functions, I'm not sure what Jacob can do to make keep this patch acceptable. Perhaps a more verbose name such as objc_addObjectiveCPredefinedGlobalIdent would make the situation better.
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 can segregate things properly by implementing a namespace (via a struct). Look at port.c or target.c as an example. The header is the shared implementation between front-ends, and the source is managed by each compiler vendor.
|
Anyone know what's going on with the linker error on Windows? |
6e217bc
to
e5cc03f
Compare
|
@yebblies I have some trouble with magicport. I have three new files: |
|
Yeah, magicport doesn't support that. One option is to handport one of the files. |
|
Is it possible to do some trick with the makefile to first port one of them and then the other one? |
|
Possible, but unlikely to be worth it. Just write a D version of objc_stubs.c by hand? |
|
Sure, that's no problem. Just wanted to make sure there's no easier way. |
e5cc03f
to
94027ed
Compare
Basic support for classes, interfaces and instance methods. This is implemented by adding a new linkage attribute, `Objective-C`, and a compiler recognized UDA, `@selector`. The linkage attribute is to be used on a class or interface. The UDA is attached to a method. The linkage attribute tells the compiler that the class should use the name mangling that matches the one used by Objective-C (same as C, no mangling) and that all methods in the class should use the Objective-C way of calling methods, see below. The calling convention for Objective-C methods and functions is the same as for C. The selector UDA tells the compiler what Objective-C selector the method should have. The selector is used in the Objective-C runtime to find the implementation of a given method. An Objective-C method call is implemented by making a regular C call to the `objc_msgSend` function in the Objective-C runtime. The signature of `objc_msgSend` looks something like this: `id objc_msgSend(id self, SEL op, ...);` * The first parameter is the object (this/self pointer) * The second parameter is the selector attached to the method * The last parameter is for all the arguments that the implementation expects The call to `objc_msgSend` should not be performed as a variadic call but instead as if it had the same signature as the method that should be called but with the two additional parameter, `self` and `op`, added first. The implementation of `objc_msgSend` will jump to the method instead of calling it. Because of the above, multiple versions exist of `objc_msgSend`. Depending on the return type of the method that is called the correct version need to be used. This depends on the ABI. This is a list of functions and for which types they're used on OS X 64bit: * objc_msgSend_stret - Used for structs too large to be returned in registries * objc_msgSend_fpret - Used for `long double` * objc_msgSend_fp2ret - Used for `_Complex long double` * objc_msgSend - Used for everything else
94027ed
to
929b56c
Compare
Implement basic support for Objective-C methods.
| */ | ||
|
|
||
| #include "arraytypes.h" | ||
| #include "class.c" |
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.
Is this deliberate? It is causing duplicate symbols when building in VS (not generating a library for the front end). Including aggregate.h and scope.h instead seems to work, too.
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 should be aggregate.h
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 a mistake, I'll fix it.
Some return types does not work, those are:
long double,_Complex long doubleand structs that are too large to fit in registers. The runtime part of this pull is in dlang/druntime#1111.The below text is in the commit message as well. I don't know if it's too long for a commit message or if there's a better place to document this.
Basic support for classes, interfaces and instance methods.
This is implemented by adding a new linkage attribute,
Objective-C,and a compiler recognized UDA,
@selector. The linkage attribute isto be used on a class or interface. The UDA is attached to a method.
The linkage attribute tells the compiler that the class should use the
name mangling that matches the one used by Objective-C
(same as C, no mangling) and that all methods in the class
should use the Objective-C way of calling methods, see below.
The calling convention for Objective-C methods and functions is the
same as for C.
The selector UDA tells the compiler what Objective-C selector the
method should have. The selector is used in the Objective-C runtime
to find the implementation of a given method.
An Objective-C method call is implemented by making a regular C call
to the
objc_msgSendfunction in the Objective-C runtime.The signature of
objc_msgSendlooks something like this:id objc_msgSend(id self, SEL op, ...);implementation expects
The call to
objc_msgSendshould not be performed as a variadiccall but instead as if it had the same signature as the method
that should be called but with the two additional parameter,
selfandop, added first. The implementation ofobjc_msgSendwill jump to the method instead of calling it.
Because of the above, multiple versions exist of
objc_msgSend.Depending on the return type of the method that is called the correct
version need to be used. This depends on the ABI. This is a list of
functions and for which types they're used on OS X 64bit:
registries
long double_Complex long double