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:
Martin 2017-10-26 20:24:03 +02:00
parent 183f97cd4e
commit 95915a8ab8
9 changed files with 130 additions and 112 deletions

View file

@ -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)

View file

@ -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();

View file

@ -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;
}

View file

@ -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.

View file

@ -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);

View file

@ -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");
}

View file

@ -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

View file

@ -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()));
}
}

View 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");
}