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

Merged
merged 68 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
68 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
9244874
Update CHANGELOG.md
LunaTheFoxgirl Nov 29, 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
4 changes: 2 additions & 2 deletions gen/abi/aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ 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 superCall) override {
// see objc/message.h for objc_msgSend selection rules
return "objc_msgSend";
return superCall ? "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 superCall) {
llvm_unreachable("Unknown Objective-C ABI");
}

Expand Down
2 changes: 1 addition & 1 deletion gen/abi/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,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 superCall);

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

Expand Down
4 changes: 2 additions & 2 deletions gen/abi/arm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@ struct ArmTargetABI : 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 superCall) override {
// see objc/message.h for objc_msgSend selection rules
if (fty.arg_sret) {
return "objc_msgSend_stret";
}
return "objc_msgSend";
return superCall ? "objc_msgSendSuper" : "objc_msgSend";
}
};

Expand Down
22 changes: 8 additions & 14 deletions gen/abi/x86-64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,21 +382,15 @@ 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 superCall) {
// see objc/message.h for objc_msgSend selection rules
assert(isDarwin);
if (fty.arg_sret) {
return "objc_msgSend_stret";
return superCall ? "objc_msgSendSuper_stret" : "objc_msgSend_stret";
}
if (ret) {
// complex long double return
if (ret->ty == TY::Tcomplex80) {
return "objc_msgSend_fp2ret";
}
// 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() && !ret->iscomplex()) {
return "objc_msgSend_fpret";
}
return "objc_msgSend";
}
return superCall ? "objc_msgSendSuper" : "objc_msgSend";
}
6 changes: 3 additions & 3 deletions gen/abi/x86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,17 +273,17 @@ struct X86TargetABI : TargetABI {
}
}

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

Expand Down
8 changes: 8 additions & 0 deletions gen/declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class CodegenVisitor : public Visitor {
m->accept(this);
}

// Objective-C protocols don't have TypeInfo.
if(decl->classKind == ClassKind::objc)
return;

// Emit TypeInfo.
IrClass *ir = getIrAggr(decl);
if (!ir->suppressTypeInfo()) {
Expand Down Expand Up @@ -205,6 +209,10 @@ class CodegenVisitor : public Visitor {
m->accept(this);
}

// TODO: Support creating objective-c exposed classes?
if (decl->classKind == ClassKind::objc)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this differs too and im not sure if it is a problem or not yet. i did call getClassReference here for non-extern classes, but you might just have a better solution elsewhere.

return;

IrClass *ir = getIrAggr(decl);

ir->getInitSymbol(/*define=*/true);
Expand Down
2 changes: 1 addition & 1 deletion gen/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype,
}

bool hasObjCSelector = false;
if (fd && fd->_linkage == LINK::objc && thistype) {
if (fd && fd->_linkage == LINK::objc) {
if (fd->objc.selector) {
hasObjCSelector = true;
} else if (fd->parent->isClassDeclaration()) {
Expand Down
12 changes: 12 additions & 0 deletions gen/llvmhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1841,6 +1841,18 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
// ourselves, DtoType below would be enough.
DtoResolveDsymbol(ad);

if (ad->classKind == ClassKind::objc) {
auto tHandle = LLType::getInt64Ty(gIR->context());
auto tOffset = DtoLoad(tHandle, gIR->objc.getIVarOffset(*ad->isClassDeclaration(), *vd, flase));

// Offset is now stored in tOffset.
LLValue *ptr = src;
ptr = DtoBitCast(ptr, getVoidPtrType());
ptr = DtoGEP1(llvm::Type::getInt8Ty(gIR->context()), ptr, tOffset);

return new DLValue(vd->type, ptr);
}

// Look up field to index or offset to apply.
auto irTypeAggr = getIrType(ad->type)->isAggr();
assert(irTypeAggr);
Expand Down
184 changes: 113 additions & 71 deletions gen/objcgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,117 +15,159 @@
#include "dmd/objc.h"
#include "gen/irstate.h"

namespace {
enum ABI { none = 0, fragile = 1, nonFragile = 2 };
ABI abi = nonFragile;
}
#define OBJC_CLASS_LIST = "__DATA,__objc_classlist";
#define OBJC_PROTOCOL_LIST = "__DATA,__objc_protolist";

bool objc_isSupported(const llvm::Triple &triple) {
if (triple.isOSDarwin()) {

// Objective-C only supported on Darwin at this time
// Additionally only Objective-C 2 is supported.
switch (triple.getArch()) {
case llvm::Triple::aarch64: // arm64 iOS, tvOS
case llvm::Triple::arm: // armv6 iOS
case llvm::Triple::thumb: // thumbv7 iOS, watchOS
case llvm::Triple::x86_64: // OSX, iOS, tvOS sim
abi = nonFragile;
return true;
case llvm::Triple::x86: // OSX, iOS, watchOS sim
abi = fragile;
return true;
return false;
default:
break;
}
}
return false;
}

llvm::GlobalVariable *getGlobal(
llvm::Module& module,
llvm::StringRef& name,
llvm::Type* type = nullptr
) {
if (type == nullptr)
type = llvm::PointerType::get(llvm::Type::getVoidTy(module.getContext()), 0);

auto var = new LLGlobalVariable(
module,
type,
false,
LLGlobalValue::ExternalLinkage,
nullptr,
name,
nullptr,
LLGlobalVariable::NotThreadLocal,
0,
true
);
return var;
}

llvm::GlobalVariable *getGlobalWithBytes(
llvm::Module& module,
llvm::StringRef name,
std::vector<llvm::Constant*> packedContents
) {
auto init = llvm::ConstantStruct::getAnon(
packedContents,
true
);

auto var = new LLGlobalVariable(
module,
init->getType(),
false,
LLGlobalValue::ExternalLinkage,
init,
name,
nullptr,

);
var->setSection("__DATA,objc_data,regular");

return var;
}

LLGlobalVariable *ObjCState::getCStringVar(const char *symbol,
const llvm::StringRef &str,
const char *section) {
auto init = llvm::ConstantDataArray::getString(module.getContext(), str);
auto var = new LLGlobalVariable(module, init->getType(), false,
LLGlobalValue::PrivateLinkage, init, symbol);
var->setSection(section);
return var;
auto init = llvm::ConstantDataArray::getString(module.getContext(), str);
auto var = new LLGlobalVariable(module, init->getType(), false,
LLGlobalValue::PrivateLinkage, init, symbol);
var->setSection(section);
return var;
}

LLGlobalVariable *ObjCState::getMethVarName(const llvm::StringRef &name) {
auto it = methVarNameMap.find(name);
if (it != methVarNameMap.end()) {
LLGlobalVariable *ObjCState::getMethodVarName(const llvm::StringRef &name) {
auto it = methVarNameMap.find(name);
if (it != methVarNameMap.end()) {
return it->second;
}
}

auto var = getCStringVar("OBJC_METH_VAR_NAME_", name,
abi == nonFragile
? "__TEXT,__objc_methname,cstring_literals"
: "__TEXT,__cstring,cstring_literals");
methVarNameMap[name] = var;
retain(var);
return var;
auto var = getCStringVar("OBJC_METH_VAR_NAME_", name,
"__TEXT,__objc_methname,cstring_literals");
methVarNameMap[name] = var;
retain(var);
return var;
}

LLGlobalVariable *ObjCState::getMethVarRef(const ObjcSelector &sel) {
llvm::StringRef s(sel.stringvalue, sel.stringlen);
auto it = methVarRefMap.find(s);
if (it != methVarRefMap.end()) {
return it->second;
}
LLGlobalVariable *ObjCState::getMethodVarRef(const ObjcSelector &sel) {
llvm::StringRef s(sel.stringvalue, sel.stringlen);
auto it = methodVarRefTable.find(s);
if (it != methodVarRefTable.end()) {
return it->second;
}

auto gvar = getMethVarName(s);
auto selref = new LLGlobalVariable(
module, gvar->getType(),
false, // prevent const elimination optimization
LLGlobalValue::PrivateLinkage, gvar, "OBJC_SELECTOR_REFERENCES_", nullptr,
LLGlobalVariable::NotThreadLocal, 0,
true
); // externally initialized

selref->setSection("__DATA,__objc_selrefs,literal_pointers,no_dead_strip");

auto gvar = getMethVarName(s);
auto selref = new LLGlobalVariable(
module, gvar->getType(),
false, // prevent const elimination optimization
LLGlobalValue::PrivateLinkage, gvar, "OBJC_SELECTOR_REFERENCES_", nullptr,
LLGlobalVariable::NotThreadLocal, 0,
true); // externally initialized
selref->setSection(
abi == nonFragile
? "__DATA,__objc_selrefs,literal_pointers,no_dead_strip"
: "__OBJC,__message_refs,literal_pointers,no_dead_strip");

// Save for later lookup and prevent optimizer elimination
methVarRefMap[s] = selref;
retain(selref);

return selref;
// Save for later lookup and prevent optimizer elimination
methVarRefMap[s] = selref;
retain(selref);

return selref;
}

void ObjCState::retain(LLConstant *sym) {
retainedSymbols.push_back(sym);
}

void ObjCState::finalize() {
if (!retainedSymbols.empty()) {
genImageInfo();
// add in references so optimizer won't remove symbols.
retainSymbols();
}
if (!retainedSymbols.empty()) {
genImageInfo();

// add in references so optimizer won't remove symbols.
retainSymbols();
}
}

void ObjCState::genImageInfo() {
// Use LLVM to generate image info
const char *section =
(abi == nonFragile ? "__DATA,__objc_imageinfo,regular,no_dead_strip"
: "__OBJC,__image_info");
module.addModuleFlag(llvm::Module::Error, "Objective-C Version",
abi); // unused?
module.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
0u); // version
module.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
llvm::MDString::get(module.getContext(), section));
module.addModuleFlag(llvm::Module::Override, "Objective-C Garbage Collection",
0u); // flags
// Use LLVM to generate image info
const char *section = "__DATA,__objc_imageinfo,regular,no_dead_strip";
module.addModuleFlag(llvm::Module::Error, "Objective-C Version", 2); // Only support ABI 2. (Non-fragile)
module.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
0u); // version
module.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
llvm::MDString::get(module.getContext(), section));
module.addModuleFlag(llvm::Module::Override, "Objective-C Garbage Collection",
0u); // flags
}

void ObjCState::retainSymbols() {
// put all objc symbols in the llvm.compiler.used array so optimizer won't
// remove.
auto arrayType = LLArrayType::get(retainedSymbols.front()->getType(),

// put all objc symbols in the llvm.compiler.used array so optimizer won't
// remove.
auto arrayType = LLArrayType::get(retainedSymbols.front()->getType(),
retainedSymbols.size());
auto usedArray = LLConstantArray::get(arrayType, retainedSymbols);
auto var = new LLGlobalVariable(module, arrayType, false,
LLGlobalValue::AppendingLinkage, usedArray,
"llvm.compiler.used");
var->setSection("llvm.metadata");
auto usedArray = LLConstantArray::get(arrayType, retainedSymbols);
auto var = new LLGlobalVariable(module, arrayType, false,
LLGlobalValue::AppendingLinkage, usedArray,
"llvm.compiler.used");
var->setSection("llvm.metadata");
}
Loading
Loading