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
Open
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
8225ff0
WIP: Objective-C support
LunaTheFoxgirl Nov 12, 2024
71ed496
Merge branch 'ldc-developers:master' into objc
LunaTheFoxgirl Nov 18, 2024
67ef162
Further work on implementation
LunaTheFoxgirl Nov 18, 2024
ffbf6ca
ObjC dynamic cast
LunaTheFoxgirl Nov 18, 2024
f2ac1d2
Add swift stub class attribute
LunaTheFoxgirl Nov 18, 2024
cb785fb
Classes, protocols and ivars
LunaTheFoxgirl Nov 19, 2024
9a9f292
Fix compilation issues
LunaTheFoxgirl Nov 19, 2024
b2c30f6
Fix objc ir codegen
LunaTheFoxgirl Nov 20, 2024
3679436
Add objc linker option
LunaTheFoxgirl Nov 20, 2024
9cbd156
Add swift stub classref get ir gen
LunaTheFoxgirl Nov 20, 2024
4246d42
Minor cleanup
LunaTheFoxgirl Nov 20, 2024
2670dbb
Fix objc link flag being added on non-darwin platforms
LunaTheFoxgirl Nov 20, 2024
58e04b3
Refactor objc gen
LunaTheFoxgirl Nov 21, 2024
da1cfbb
remove use of std::nullopt
LunaTheFoxgirl Nov 21, 2024
bcaff89
Emit protocol tables
LunaTheFoxgirl Nov 22, 2024
bc64a73
Remove unused variable
LunaTheFoxgirl Nov 22, 2024
a28981a
Formatting
LunaTheFoxgirl Nov 22, 2024
a7f6ef0
Fix build in release mode. Thanks for nothing, c++.
LunaTheFoxgirl Nov 22, 2024
3895396
Fix consistency
LunaTheFoxgirl Nov 22, 2024
92bbe08
Fix dynamic casts
LunaTheFoxgirl Nov 22, 2024
0fd521d
Fix tocall parentfd ref and arm msgsend call
LunaTheFoxgirl Nov 23, 2024
627db4f
Make instance variables work
LunaTheFoxgirl Nov 23, 2024
dd062ea
Implicitly add isa pointer to objc classes.
LunaTheFoxgirl Nov 23, 2024
37a701d
Fix protocol referencing & allow pragma mangle
LunaTheFoxgirl Nov 23, 2024
f0a5b4c
Fix protocol linkage
LunaTheFoxgirl Nov 23, 2024
1b2cc5d
Fix direct call support
LunaTheFoxgirl Nov 23, 2024
8212b12
always generate var type for methods
LunaTheFoxgirl Nov 24, 2024
aa9b892
Fix test 16096a
LunaTheFoxgirl Nov 24, 2024
29c9616
Fix extern ivar symbol gen, retain method decls
LunaTheFoxgirl Nov 24, 2024
a885a90
Remove arm32 and x86 support
LunaTheFoxgirl Nov 25, 2024
7d857c9
Check method and ivar info before pushing to member list
LunaTheFoxgirl Nov 25, 2024
def16ff
Make ObjcMethod info untyped.
LunaTheFoxgirl Nov 25, 2024
3b86873
Make ivar and method gen more robust
LunaTheFoxgirl Nov 25, 2024
056e457
Generate optional protocol symbols
LunaTheFoxgirl Nov 25, 2024
c1a76f8
Use bitcasting instead of creating multiple type defs
LunaTheFoxgirl Nov 25, 2024
442f248
Fix invalid protocol list struct gen
LunaTheFoxgirl Nov 25, 2024
9b32dc8
More codegen robustness
LunaTheFoxgirl Nov 25, 2024
19189ea
emit protocol table as const
LunaTheFoxgirl Nov 25, 2024
091bdb2
Make protocol table anon struct
LunaTheFoxgirl Nov 26, 2024
d252845
Fix callable type, generate protocol_list_t properly.
LunaTheFoxgirl Nov 26, 2024
ed01dbc
Cast vthis to argtype
LunaTheFoxgirl Nov 26, 2024
47638ed
Handle protorefs and classrefs properly
LunaTheFoxgirl Nov 26, 2024
9c63811
seperate label ref and deref
LunaTheFoxgirl Nov 26, 2024
2606073
Fix method lookup
LunaTheFoxgirl Nov 26, 2024
b561bd4
Enable objective-c tests
LunaTheFoxgirl Nov 26, 2024
d106402
Enable objc_call_static test
LunaTheFoxgirl Nov 26, 2024
9690109
Scan both classes and protocols for method ref
LunaTheFoxgirl Nov 26, 2024
9c4700a
Enable objective-c tests on arm as well.
LunaTheFoxgirl Nov 26, 2024
05ab567
supress objc linker warning in tests
LunaTheFoxgirl Nov 26, 2024
f9fd977
Fix class and protocol gen structure
LunaTheFoxgirl Nov 26, 2024
cdae5b8
Fix objc_protocol_sections test
LunaTheFoxgirl Nov 26, 2024
b923a57
ObjcMethod only get callee for functions with bodies
LunaTheFoxgirl Nov 26, 2024
4d8ec8b
Fix protocol class method gen
LunaTheFoxgirl Nov 26, 2024
ccec2ea
Make ObjcMethod anon again
LunaTheFoxgirl Nov 26, 2024
c8e743e
Fix missing emit calls
LunaTheFoxgirl Nov 26, 2024
f9bf25a
Fix classref gen
LunaTheFoxgirl Nov 26, 2024
f577f51
Implement some of the requested changes
LunaTheFoxgirl Nov 28, 2024
0d84d40
Enable compilable tests
LunaTheFoxgirl Nov 28, 2024
8ac9a36
Fix property selector gen, ugly hack for final funcs.
LunaTheFoxgirl Nov 28, 2024
5410e04
Fix segfault in referencing fd->type
LunaTheFoxgirl Nov 28, 2024
1fc06e4
Refactor implementation
LunaTheFoxgirl Nov 28, 2024
e6d6548
Fix null references in class and method lookup
LunaTheFoxgirl Nov 28, 2024
db91254
include unordered_map
LunaTheFoxgirl Nov 28, 2024
c9bed7a
Get functionality on-par with prev impl.
LunaTheFoxgirl Nov 28, 2024
7423d0a
Fix super context calls
LunaTheFoxgirl Nov 28, 2024
5d86126
Move -L-w flag to d_do_test and use IN_LLVM in objc.d/h
LunaTheFoxgirl Nov 28, 2024
fd35f83
add LDC version tag to -L-w flag
LunaTheFoxgirl Nov 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ immutable Msgtable[] msgtable =
{ "udaHidden", "_hidden" },
{ "udaNoSanitize", "noSanitize" },
{ "udaNoSplitStack", "_noSplitStack" },
{ "udaSwiftStub", "swift"},

// IN_LLVM: DCompute specific types and functionss
{ "dcompute" },
Expand Down
56 changes: 56 additions & 0 deletions dmd/objc.d
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ extern (C++) struct ObjcClassDeclaration
/// `true` if this class is externally defined.
bool isExtern = false;

/// `true` if this class is a Swift stub
bool isSwiftStub = false;

LunaTheFoxgirl marked this conversation as resolved.
Show resolved Hide resolved
/// Name of this class.
Identifier identifier;

Expand Down Expand Up @@ -264,6 +267,16 @@ extern(C++) abstract class Objc
*/
abstract void setAsOptional(FuncDeclaration functionDeclaration, Scope* sc) const;

/**
* Marks the given class as a Swift stub class.
*
* Params:
* cd = the class declaration to set as a swift stub
* sc = the scope from the semantic phase
*/
version(IN_LLVM)
abstract void setAsSwiftStub(ClassDeclaration cd, Scope* sc) const;

/**
* Validates function declarations declared optional.
*
Expand Down Expand Up @@ -452,6 +465,12 @@ static if (!IN_LLVM)
// noop
}

version(IN_LLVM)
override void setAsSwiftStub(ClassDeclaration, Scope*) const
{
// noop
}

override void validateOptional(FuncDeclaration) const
{
// noop
Expand Down Expand Up @@ -532,6 +551,7 @@ version (IN_LLVM) {} else
{
cd.classKind = ClassKind.objc;
cd.objc.isExtern = (cd.storage_class & STC.extern_) > 0;
this.setAsSwiftStub(cd, cd._scope);
}

override void setObjc(InterfaceDeclaration id)
Expand Down Expand Up @@ -826,6 +846,42 @@ version (IN_LLVM) {} else
errorSupplemental(expression.loc, "`tupleof` is not available for members " ~
"of Objective-C classes. Please use the Objective-C runtime instead");
}

version(IN_LLVM) {
override void setAsSwiftStub(ClassDeclaration cd, Scope* sc) const
{
const count = declaredAsSwiftStubCount(cd, sc);
cd.objc.isSwiftStub = count > 0;

if (count > 1)
.error(cd.loc, "%s `%s` can only declare a class as a swift stub once", cd.kind, cd.toPrettyChars);
}

/// Returns: the number of times `cd` has been declared as optional.
private int declaredAsSwiftStubCount(ClassDeclaration cd, Scope* sc) const
{
int count;

foreachUda(cd, sc, (e) {
if (!e.isTypeExp())
return 0;

auto typeExp = e.isTypeExp();

if (typeExp.type.ty != Tenum)
return 0;

auto typeEnum = cast(TypeEnum) typeExp.type;

if (isCoreUda(typeEnum.sym, Id.udaSwiftStub))
count++;

return 0;
});

return count;
}
}
}

/*
Expand Down
4 changes: 4 additions & 0 deletions dmd/objc.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct ObjcClassDeclaration
{
d_bool isMeta;
d_bool isExtern;
d_bool isSwiftStub;
LunaTheFoxgirl marked this conversation as resolved.
Show resolved Hide resolved

Identifier* identifier;
ClassDeclaration* classDeclaration;
Expand Down Expand Up @@ -67,6 +68,9 @@ class Objc
virtual void checkLinkage(FuncDeclaration* fd) = 0;
virtual bool isVirtual(const FuncDeclaration*) const = 0;
virtual void setAsOptional(FuncDeclaration *fd, Scope *sc) const = 0;
#if IN_LLVM
virtual void setAsSwiftStub(ClassDeclaration* cd, Scope *sc) const = 0;
#endif
virtual void validateOptional(FuncDeclaration *fd) const = 0;
virtual ClassDeclaration* getParent(FuncDeclaration*, ClassDeclaration*) const = 0;
virtual void addToClassMethodList(FuncDeclaration*, ClassDeclaration*) const = 0;
Expand Down
19 changes: 19 additions & 0 deletions driver/linker-gcc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ static llvm::cl::opt<bool> linkNoCpp(
"link-no-cpp", llvm::cl::ZeroOrMore, llvm::cl::Hidden,
llvm::cl::desc("Disable automatic linking with the C++ standard library."));

static llvm::cl::opt<bool> linkNoObjc(
"link-no-objc", llvm::cl::ZeroOrMore, llvm::cl::Hidden,
llvm::cl::desc("Disable automatic linking with the Objective-C runtime library."));

//////////////////////////////////////////////////////////////////////////////

namespace {
Expand All @@ -72,6 +76,7 @@ class ArgsBuilder {
virtual void addXRayLinkFlags(const llvm::Triple &triple);
virtual bool addCompilerRTArchiveLinkFlags(llvm::StringRef baseName,
const llvm::Triple &triple);
virtual void addObjcStdlibLinkFlags(const llvm::Triple &triple);

virtual void addLinker();
virtual void addUserSwitches();
Expand Down Expand Up @@ -467,6 +472,13 @@ void ArgsBuilder::addCppStdlibLinkFlags(const llvm::Triple &triple) {
}
}

void ArgsBuilder::addObjcStdlibLinkFlags(const llvm::Triple &triple) {
if (linkNoObjc)
return;

args.push_back("-lobjc");
}

// Adds all required link flags for PGO.
void ArgsBuilder::addProfileRuntimeLinkFlags(const llvm::Triple &triple) {
const auto searchPaths =
Expand Down Expand Up @@ -725,6 +737,13 @@ void ArgsBuilder::addDefaultPlatformLibs() {
break;
}

if (triple.isOSDarwin()) {

// libobjc is more or less required, so we link against it here.
// This could be prettier, though.
addObjcStdlibLinkFlags(triple);
}

if (triple.isWindowsGNUEnvironment()) {
// This is really more of a kludge, as linking in the Winsock functions
// should be handled by the pragma(lib, ...) in std.socket, but it
Expand Down
15 changes: 8 additions & 7 deletions gen/abi/aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ using namespace dmd;
*/
struct AArch64TargetABI : TargetABI {
private:
const bool isDarwin;
IndirectByvalRewrite indirectByvalRewrite;
ArgTypesRewrite argTypesRewrite;

bool isAAPCS64VaList(Type *t) {
if (isDarwin)
if (isDarwin())
return false;

// look for a __va_list struct in a `std` C++ namespace
Expand All @@ -51,7 +50,7 @@ struct AArch64TargetABI : TargetABI {
}

public:
AArch64TargetABI() : isDarwin(global.params.targetTriple->isOSDarwin()) {}
AArch64TargetABI() {}

bool returnInArg(TypeFunction *tf, bool) override {
if (tf->isref()) {
Expand Down Expand Up @@ -108,7 +107,7 @@ struct AArch64TargetABI : TargetABI {
}

// https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html#//apple_ref/doc/uid/TP40013702-SW1
if (isDarwin) {
if (isDarwin()) {
if (auto ts = tb->isTypeStruct()) {
if (ts->sym->fields.empty() && ts->sym->isPOD()) {
fty.args.erase(fty.args.begin() + i);
Expand Down Expand Up @@ -166,7 +165,7 @@ struct AArch64TargetABI : TargetABI {
}

Type *vaListType() override {
if (isDarwin)
if (isDarwin())
return TargetABI::vaListType(); // char*

// We need to pass the actual va_list type for correct mangling. Simply
Expand All @@ -176,9 +175,11 @@ struct AArch64TargetABI : TargetABI {
return TypeIdentifier::create(Loc(), Identifier::idPool("__va_list"));
}

const char *objcMsgSendFunc(Type *ret, IrFuncTy &fty) override {
const char *objcMsgSendFunc(Type *ret, IrFuncTy &fty, bool directcall) override {
assert(isDarwin());

// see objc/message.h for objc_msgSend selection rules
return "objc_msgSend";
return directcall ? "objc_msgSendSuper" : "objc_msgSend";
}
};

Expand Down
2 changes: 1 addition & 1 deletion gen/abi/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ Type *TargetABI::vaListType() {

//////////////////////////////////////////////////////////////////////////////

const char *TargetABI::objcMsgSendFunc(Type *ret, IrFuncTy &fty) {
const char *TargetABI::objcMsgSendFunc(Type *ret, IrFuncTy &fty, bool directcall) {
llvm_unreachable("Unknown Objective-C ABI");
}

Expand Down
8 changes: 7 additions & 1 deletion gen/abi/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ struct ABIRewrite {

// interface called by codegen
struct TargetABI {
public:
virtual ~TargetABI() = default;

/// Returns the ABI for the target we're compiling for
Expand Down Expand Up @@ -117,6 +118,11 @@ struct TargetABI {
global.params.targetTriple->getOS() == llvm::Triple::NetBSD;
}

/// Returns true if the target is darwin-based.
bool isDarwin() {
return global.params.targetTriple->isOSDarwin();
}
LunaTheFoxgirl marked this conversation as resolved.
Show resolved Hide resolved

/// Returns true if the D function uses sret (struct return).
/// `needsThis` is true if the function type is for a non-static member
/// function.
Expand Down Expand Up @@ -171,7 +177,7 @@ struct TargetABI {
virtual Type *vaListType();

/// Returns Objective-C message send function
virtual const char *objcMsgSendFunc(Type *ret, IrFuncTy &fty);
virtual const char *objcMsgSendFunc(Type *ret, IrFuncTy &fty, bool directcall);

/***** Static Helpers *****/

Expand Down
8 changes: 0 additions & 8 deletions gen/abi/arm.cpp
LunaTheFoxgirl marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,6 @@ struct ArmTargetABI : TargetABI {
// solution is found there, this should be adapted).
return TypeIdentifier::create(Loc(), Identifier::idPool("__va_list"));
}

const char *objcMsgSendFunc(Type *ret, IrFuncTy &fty) override {
// see objc/message.h for objc_msgSend selection rules
if (fty.arg_sret) {
return "objc_msgSend_stret";
}
return "objc_msgSend";
}
};

TargetABI *getArmTargetABI() { return new ArmTargetABI; }
29 changes: 12 additions & 17 deletions gen/abi/x86-64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ struct X86_64TargetABI : TargetABI {

Type *vaListType() override;

const char *objcMsgSendFunc(Type *ret, IrFuncTy &fty) override;
const char *objcMsgSendFunc(Type *ret, IrFuncTy &fty, bool directcall) override;

private:
LLType *getValistType();
Expand Down Expand Up @@ -196,9 +196,6 @@ struct X86_64TargetABI : TargetABI {
}
};

// The public getter for abi.cpp
TargetABI *getX86_64TargetABI() { return new X86_64TargetABI; }

bool X86_64TargetABI::returnInArg(TypeFunction *tf, bool) {
if (tf->isref()) {
return false;
Expand Down Expand Up @@ -382,21 +379,19 @@ Type *X86_64TargetABI::vaListType() {
TypeIdentifier::create(Loc(), Identifier::idPool("__va_list_tag")));
}

const char *X86_64TargetABI::objcMsgSendFunc(Type *ret,
IrFuncTy &fty) {
const char *X86_64TargetABI::objcMsgSendFunc(Type *ret, IrFuncTy &fty, bool directcall) {
assert(isDarwin());

// see objc/message.h for objc_msgSend selection rules
if (fty.arg_sret) {
return "objc_msgSend_stret";
return directcall ? "objc_msgSendSuper_stret" : "objc_msgSend_stret";
}
if (ret) {
// complex long double return
if (ret->ty == TY::Tcomplex80) {
return "objc_msgSend_fp2ret";
LunaTheFoxgirl marked this conversation as resolved.
Show resolved Hide resolved
}
// long double return
if (ret->ty == TY::Tfloat80 || ret->ty == TY::Timaginary80) {
return "objc_msgSend_fpret";
}
// float, double, long double return
if (ret && ret->isfloating()) {
return ret->ty == TY::Tcomplex80 ? "objc_msgSend_fp2ret" : "objc_msgSend_fpret";
}
return "objc_msgSend";
return directcall ? "objc_msgSendSuper" : "objc_msgSend";
}

// The public getter for abi.cpp
TargetABI *getX86_64TargetABI() { return new X86_64TargetABI; }
19 changes: 2 additions & 17 deletions gen/abi/x86.cpp
LunaTheFoxgirl marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@
using namespace dmd;

struct X86TargetABI : TargetABI {
const bool isDarwin;
const bool isMSVC;
bool returnStructsInRegs;
IntegerRewrite integerRewrite;
IndirectByvalRewrite indirectByvalRewrite;

X86TargetABI()
: isDarwin(global.params.targetTriple->isOSDarwin()),
isMSVC(global.params.targetTriple->isWindowsMSVCEnvironment()) {
: isMSVC(global.params.targetTriple->isWindowsMSVCEnvironment()) {
using llvm::Triple;
auto os = global.params.targetTriple->getOS();
returnStructsInRegs =
Expand Down Expand Up @@ -230,7 +228,7 @@ struct X86TargetABI : TargetABI {
// Clang does not pass empty structs, while it seems that GCC does,
// at least on Linux x86. We don't know whether the C compiler will
// be Clang or GCC, so just assume Clang on Darwin and G++ on Linux.
if (externD || !isDarwin)
if (externD || !isDarwin())
return;

size_t i = 0;
Expand Down Expand Up @@ -272,19 +270,6 @@ struct X86TargetABI : TargetABI {
}
}
}

const char *objcMsgSendFunc(Type *ret, IrFuncTy &fty) override {
// see objc/message.h for objc_msgSend selection rules
assert(isDarwin);
if (fty.arg_sret) {
return "objc_msgSend_stret";
}
// float, double, long double return
if (ret && ret->isfloating() && !ret->iscomplex()) {
return "objc_msgSend_fpret";
}
return "objc_msgSend";
}
};

// The public getter for abi.cpp.
Expand Down
Loading
Loading