mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 23:50:43 +03:00
Fix and refactor Objective-C state
Tie the state to an LLVM module/object file instead of having a global one. And finalize it once per LLVM module instead of once per D module (previously, as part of ModuleInfo generation). Fixes issue #2388.
This commit is contained in:
parent
183f97cd4e
commit
95915a8ab8
9 changed files with 130 additions and 112 deletions
|
@ -32,7 +32,7 @@ version (IN_LLVM)
|
|||
{
|
||||
Statement asmSemantic(AsmStatement s, Scope* sc);
|
||||
RET retStyle(TypeFunction tf);
|
||||
void objc_initSymbols(); // in gen/objcgen.cpp
|
||||
void objc_initSymbols() {}
|
||||
}
|
||||
}
|
||||
else version (NoBackend)
|
||||
|
|
|
@ -247,6 +247,8 @@ void CodeGenerator::finishLLModule(Module *m) {
|
|||
}
|
||||
|
||||
void CodeGenerator::writeAndFreeLLModule(const char *filename) {
|
||||
ir_->objc.finalize();
|
||||
|
||||
// Issue #1829: make sure all replaced global variables are replaced
|
||||
// everywhere.
|
||||
ir_->replaceGlobals();
|
||||
|
|
|
@ -35,7 +35,7 @@ IRScope &IRScope::operator=(const IRScope &rhs) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
IRState::IRState(const char *name, llvm::LLVMContext &context)
|
||||
: module(name, context), DBuilder(this) {
|
||||
: module(name, context), DBuilder(this), objc(module) {
|
||||
ir.state = this;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "aggregate.h"
|
||||
#include "root.h"
|
||||
#include "gen/dibuilder.h"
|
||||
#include "gen/objcgen.h"
|
||||
#include "ir/iraggr.h"
|
||||
#include "ir/irvar.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
@ -105,7 +106,7 @@ struct IRAsmBlock {
|
|||
retfixup(nullptr) {}
|
||||
};
|
||||
|
||||
// represents the module
|
||||
// represents the LLVM module (object file)
|
||||
struct IRState {
|
||||
private:
|
||||
std::vector<std::pair<llvm::GlobalVariable *, llvm::Constant *>>
|
||||
|
@ -125,6 +126,8 @@ public:
|
|||
|
||||
LLStructType *moduleRefType = nullptr;
|
||||
|
||||
ObjCState objc;
|
||||
|
||||
// Stack of currently codegen'd functions (more than one for lambdas or other
|
||||
// nested functions, inlining-only codegen'ing, etc.), and some convenience
|
||||
// accessors for the top-most one.
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/mangling.h"
|
||||
#include "gen/objcgen.h"
|
||||
#include "gen/rttibuilder.h"
|
||||
#include "ir/irfunction.h"
|
||||
#include "ir/irmodule.h"
|
||||
|
@ -306,8 +305,6 @@ llvm::GlobalVariable *genModuleInfo(Module *m) {
|
|||
const auto at = llvm::ArrayType::get(it, len);
|
||||
b.push(toConstantArray(it, at, name, len, false));
|
||||
|
||||
objc_Module_genmoduleinfo_classes();
|
||||
|
||||
// Create a global symbol with the above initialiser.
|
||||
LLGlobalVariable *moduleInfoSym = getIrModule(m)->moduleInfoSymbol();
|
||||
b.finalize(moduleInfoSym->getType()->getPointerElementType(), moduleInfoSym);
|
||||
|
|
161
gen/objcgen.cpp
161
gen/objcgen.cpp
|
@ -9,89 +9,16 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gen/objcgen.h"
|
||||
#include "mtype.h"
|
||||
#include "objc.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/objcgen.h"
|
||||
|
||||
namespace {
|
||||
// Were any Objective-C symbols generated?
|
||||
bool hasSymbols;
|
||||
|
||||
enum ABI {
|
||||
none = 0,
|
||||
fragile = 1,
|
||||
nonFragile = 2
|
||||
};
|
||||
|
||||
enum ABI { none = 0, fragile = 1, nonFragile = 2 };
|
||||
ABI abi = nonFragile;
|
||||
|
||||
// symbols that shouldn't be optimized away
|
||||
std::vector<LLConstant *> retainedSymbols;
|
||||
|
||||
llvm::StringMap<LLGlobalVariable *> methVarNameMap;
|
||||
llvm::StringMap<LLGlobalVariable *> methVarRefMap;
|
||||
|
||||
void retain(LLConstant *sym) {
|
||||
retainedSymbols.push_back(DtoBitCast(sym, getVoidPtrType()));
|
||||
}
|
||||
|
||||
void retainSymbols() {
|
||||
// put all objc symbols in the llvm.compiler.used array so optimizer won't
|
||||
// remove. Should do just once per module.
|
||||
auto arrayType = LLArrayType::get(getVoidPtrType(), retainedSymbols.size());
|
||||
auto usedArray = LLConstantArray::get(arrayType, retainedSymbols);
|
||||
auto var = new LLGlobalVariable
|
||||
(gIR->module, usedArray->getType(), false,
|
||||
LLGlobalValue::AppendingLinkage,
|
||||
usedArray,
|
||||
"llvm.compiler.used");
|
||||
var->setSection("llvm.metadata");
|
||||
}
|
||||
|
||||
void genImageInfo() {
|
||||
// Use LLVM to generate image info
|
||||
const char *section = (abi == nonFragile ?
|
||||
"__DATA,__objc_imageinfo,regular,no_dead_strip" :
|
||||
"__OBJC,__image_info");
|
||||
gIR->module.addModuleFlag(llvm::Module::Error,
|
||||
"Objective-C Version", abi); // unused?
|
||||
gIR->module.addModuleFlag(llvm::Module::Error,
|
||||
"Objective-C Image Info Version", 0u); // version
|
||||
gIR->module.addModuleFlag(llvm::Module::Error,
|
||||
"Objective-C Image Info Section",
|
||||
llvm::MDString::get(gIR->context(), section));
|
||||
gIR->module.addModuleFlag(llvm::Module::Override,
|
||||
"Objective-C Garbage Collection", 0u); // flags
|
||||
}
|
||||
|
||||
LLGlobalVariable *getCStringVar(const char *symbol,
|
||||
const llvm::StringRef &str,
|
||||
const char *section) {
|
||||
auto init = llvm::ConstantDataArray::getString(gIR->context(), str);
|
||||
auto var = new LLGlobalVariable
|
||||
(gIR->module, init->getType(), false,
|
||||
LLGlobalValue::PrivateLinkage, init, symbol);
|
||||
var->setSection(section);
|
||||
return var;
|
||||
}
|
||||
|
||||
LLGlobalVariable *getMethVarName(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;
|
||||
}
|
||||
} // end local stuff
|
||||
|
||||
bool objc_isSupported(const llvm::Triple &triple) {
|
||||
if (triple.isOSDarwin()) {
|
||||
// Objective-C only supported on Darwin at this time
|
||||
|
@ -112,15 +39,32 @@ bool objc_isSupported(const llvm::Triple &triple) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// called by the ddmd.objc.Supported ctor
|
||||
void objc_initSymbols() {
|
||||
hasSymbols = false;
|
||||
retainedSymbols.clear();
|
||||
methVarNameMap.clear();
|
||||
methVarRefMap.clear();
|
||||
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;
|
||||
}
|
||||
|
||||
LLGlobalVariable *objc_getMethVarRef(const ObjcSelector &sel) {
|
||||
LLGlobalVariable *ObjCState::getMethVarName(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;
|
||||
}
|
||||
|
||||
LLGlobalVariable *ObjCState::getMethVarRef(const ObjcSelector &sel) {
|
||||
llvm::StringRef s(sel.stringvalue, sel.stringlen);
|
||||
auto it = methVarRefMap.find(s);
|
||||
if (it != methVarRefMap.end()) {
|
||||
|
@ -128,30 +72,59 @@ LLGlobalVariable *objc_getMethVarRef(const ObjcSelector &sel) {
|
|||
}
|
||||
|
||||
auto gvar = getMethVarName(s);
|
||||
auto selref = new LLGlobalVariable
|
||||
(gIR->module, gvar->getType(),
|
||||
auto selref = new LLGlobalVariable(
|
||||
module, gvar->getType(),
|
||||
false, // prevent const elimination optimization
|
||||
LLGlobalValue::PrivateLinkage,
|
||||
gvar,
|
||||
"OBJC_SELECTOR_REFERENCES_",
|
||||
nullptr, LLGlobalVariable::NotThreadLocal, 0,
|
||||
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");
|
||||
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);
|
||||
hasSymbols = true;
|
||||
|
||||
return selref;
|
||||
}
|
||||
|
||||
void objc_Module_genmoduleinfo_classes() {
|
||||
if (hasSymbols) {
|
||||
void ObjCState::retain(LLConstant *sym) {
|
||||
retainedSymbols.push_back(DtoBitCast(sym, getVoidPtrType()));
|
||||
}
|
||||
|
||||
void ObjCState::finalize() {
|
||||
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
|
||||
}
|
||||
|
||||
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(),
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -14,15 +14,44 @@
|
|||
#ifndef LDC_GEN_OBJCGEN_H
|
||||
#define LDC_GEN_OBJCGEN_H
|
||||
|
||||
#include <vector>
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
struct ObjcSelector;
|
||||
namespace llvm {
|
||||
class Constant;
|
||||
class GlobalVariable;
|
||||
class Module;
|
||||
class Triple;
|
||||
}
|
||||
|
||||
bool objc_isSupported(const llvm::Triple &triple);
|
||||
void objc_initSymbols();
|
||||
void objc_Module_genmoduleinfo_classes();
|
||||
llvm::GlobalVariable *objc_getMethVarRef(const ObjcSelector &sel);
|
||||
|
||||
// Objective-C state tied to an LLVM module (object file).
|
||||
class ObjCState {
|
||||
public:
|
||||
ObjCState(llvm::Module &module) : module(module) {}
|
||||
|
||||
llvm::GlobalVariable *getMethVarRef(const ObjcSelector &sel);
|
||||
void finalize();
|
||||
|
||||
private:
|
||||
llvm::Module &module;
|
||||
|
||||
// symbols that shouldn't be optimized away
|
||||
std::vector<llvm::Constant *> retainedSymbols;
|
||||
|
||||
llvm::StringMap<llvm::GlobalVariable *> methVarNameMap;
|
||||
llvm::StringMap<llvm::GlobalVariable *> methVarRefMap;
|
||||
|
||||
llvm::GlobalVariable *getCStringVar(const char *symbol,
|
||||
const llvm::StringRef &str,
|
||||
const char *section);
|
||||
llvm::GlobalVariable *getMethVarName(const llvm::StringRef &name);
|
||||
void retain(llvm::Constant *sym);
|
||||
|
||||
void genImageInfo();
|
||||
void retainSymbols();
|
||||
};
|
||||
|
||||
#endif // LDC_GEN_OBJCGEN_H
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/nested.h"
|
||||
#include "gen/objcgen.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/runtime.h"
|
||||
#include "ir/irfunction.h"
|
||||
|
@ -774,7 +773,7 @@ private:
|
|||
assert(dfnval);
|
||||
const auto selector = dfnval->func->selector;
|
||||
assert(selector);
|
||||
LLGlobalVariable *selptr = objc_getMethVarRef(*selector);
|
||||
LLGlobalVariable *selptr = gIR->objc.getMethVarRef(*selector);
|
||||
args.push_back(DtoBitCast(DtoLoad(selptr), getVoidPtrType()));
|
||||
}
|
||||
}
|
||||
|
|
15
tests/compilable/objc_gh2388.d
Normal file
15
tests/compilable/objc_gh2388.d
Normal file
|
@ -0,0 +1,15 @@
|
|||
// REQUIRES: Darwin
|
||||
// RUN: %ldc -c -singleobj %s %S/objc_gh2387.d
|
||||
|
||||
void alloc()
|
||||
{
|
||||
NSObject o;
|
||||
o.alloc();
|
||||
}
|
||||
|
||||
extern (Objective-C):
|
||||
|
||||
interface NSObject
|
||||
{
|
||||
NSObject alloc() @selector("alloc");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue