mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-27 13:40:33 +03:00

* WIP: Objective-C support * Further work on implementation * ObjC dynamic cast * Add swift stub class attribute * Classes, protocols and ivars * Fix compilation issues * Fix objc ir codegen * Add objc linker option * Add swift stub classref get ir gen * Minor cleanup * Fix objc link flag being added on non-darwin platforms * Refactor objc gen * remove use of std::nullopt * Emit protocol tables * Remove unused variable * Formatting * Fix build in release mode. Thanks for nothing, c++. * Fix consistency * Fix dynamic casts * Fix tocall parentfd ref and arm msgsend call * Make instance variables work * Implicitly add isa pointer to objc classes. * Fix protocol referencing & allow pragma mangle * Fix protocol linkage * Fix direct call support * always generate var type for methods * Fix test 16096a * Fix extern ivar symbol gen, retain method decls * Remove arm32 and x86 support * Check method and ivar info before pushing to member list * Make ObjcMethod info untyped. * Make ivar and method gen more robust * Generate optional protocol symbols * Use bitcasting instead of creating multiple type defs * Fix invalid protocol list struct gen * More codegen robustness * emit protocol table as const * Make protocol table anon struct * Fix callable type, generate protocol_list_t properly. * Cast vthis to argtype * Handle protorefs and classrefs properly * seperate label ref and deref * Fix method lookup * Enable objective-c tests * Enable objc_call_static test * Scan both classes and protocols for method ref * Enable objective-c tests on arm as well. * supress objc linker warning in tests * Fix class and protocol gen structure * Fix objc_protocol_sections test * ObjcMethod only get callee for functions with bodies * Fix protocol class method gen * Make ObjcMethod anon again * Fix missing emit calls * Fix classref gen * Implement some of the requested changes * Enable compilable tests * Fix property selector gen, ugly hack for final funcs. * Fix segfault in referencing fd->type * Refactor implementation * Fix null references in class and method lookup * include unordered_map * Get functionality on-par with prev impl. * Fix super context calls * Move -L-w flag to d_do_test and use IN_LLVM in objc.d/h * add LDC version tag to -L-w flag * Update CHANGELOG.md
166 lines
4.9 KiB
C++
166 lines
4.9 KiB
C++
//===-- irtypeclass.cpp ---------------------------------------------------===//
|
||
//
|
||
// LDC – the LLVM D compiler
|
||
//
|
||
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||
// file for details.
|
||
//
|
||
//===----------------------------------------------------------------------===//
|
||
|
||
#include "ir/irtypeclass.h"
|
||
|
||
#include "dmd/aggregate.h"
|
||
#include "dmd/declaration.h"
|
||
#include "dmd/dsymbol.h"
|
||
#include "dmd/errors.h"
|
||
#include "dmd/mtype.h"
|
||
#include "dmd/target.h"
|
||
#include "dmd/template.h"
|
||
#include "gen/functions.h"
|
||
#include "gen/irstate.h"
|
||
#include "gen/llvmhelpers.h"
|
||
#include "gen/logger.h"
|
||
#include "gen/tollvm.h"
|
||
#include "llvm/IR/DerivedTypes.h"
|
||
|
||
IrTypeClass::IrTypeClass(ClassDeclaration *cd)
|
||
: IrTypeAggr(cd), cd(cd), tc(static_cast<TypeClass *>(cd->type)) {
|
||
vtbl_type = LLArrayType::get(getOpaquePtrType(), cd->vtbl.length);
|
||
}
|
||
|
||
void IrTypeClass::addClassData(AggrTypeBuilder &builder,
|
||
ClassDeclaration *currCd) {
|
||
// First, recursively add the fields for our base class and interfaces, if
|
||
// any.
|
||
if (currCd->baseClass) {
|
||
addClassData(builder, currCd->baseClass);
|
||
}
|
||
|
||
if (currCd->vtblInterfaces && currCd->vtblInterfaces->length > 0) {
|
||
// KLUDGE: The first pointer in the vtbl will be of type object.Interface;
|
||
// extract that from the "well-known" object.TypeInfo_Class definition.
|
||
// For C++ interfaces, this vtbl entry has to be omitted
|
||
|
||
builder.alignCurrentOffset(target.ptrsize);
|
||
|
||
for (auto b : *currCd->vtblInterfaces) {
|
||
IF_LOG Logger::println("Adding interface vtbl for %s",
|
||
b->sym->toPrettyChars());
|
||
|
||
// add to the interface map
|
||
addInterfaceToMap(b->sym, builder.currentFieldIndex());
|
||
auto vtblTy = LLArrayType::get(getOpaquePtrType(), b->sym->vtbl.length);
|
||
builder.addType(llvm::PointerType::get(vtblTy, 0), target.ptrsize);
|
||
|
||
++num_interface_vtbls;
|
||
}
|
||
}
|
||
|
||
// Finally, the data members for this class.
|
||
builder.addAggregate(currCd);
|
||
}
|
||
|
||
IrTypeClass *IrTypeClass::get(ClassDeclaration *cd) {
|
||
const auto t = new IrTypeClass(cd);
|
||
getIrType(cd->type) = t;
|
||
return t;
|
||
}
|
||
|
||
llvm::Type *IrTypeClass::getLLType() { return getOpaquePtrType(); }
|
||
|
||
// Lazily build the actual IR struct type when needed.
|
||
// Note that it is this function that initializes most fields!
|
||
llvm::Type *IrTypeClass::getMemoryLLType() {
|
||
if (!isaStruct(type)->isOpaque())
|
||
return type;
|
||
|
||
IF_LOG Logger::println("Building class type %s @ %s", cd->toPrettyChars(),
|
||
cd->loc.toChars());
|
||
LOG_SCOPE;
|
||
|
||
const unsigned instanceSize = cd->structsize;
|
||
IF_LOG Logger::println("Instance size: %u", instanceSize);
|
||
|
||
AggrTypeBuilder builder;
|
||
|
||
// Objective-C just has an ISA pointer, so just
|
||
// throw that in there.
|
||
if (cd->classKind == ClassKind::objc) {
|
||
builder.addType(getOpaquePtrType(), target.ptrsize);
|
||
isaStruct(type)->setBody(builder.defaultTypes(), builder.isPacked());
|
||
return type;
|
||
}
|
||
|
||
// add vtbl
|
||
builder.addType(llvm::PointerType::get(vtbl_type, 0), target.ptrsize);
|
||
|
||
if (cd->isInterfaceDeclaration()) {
|
||
// interfaces are just a vtable
|
||
num_interface_vtbls =
|
||
cd->vtblInterfaces ? cd->vtblInterfaces->length : 0;
|
||
} else {
|
||
// classes have monitor and fields
|
||
if (!cd->isCPPclass() && !cd->isCPPinterface()) {
|
||
// add monitor
|
||
builder.addType(getOpaquePtrType(), target.ptrsize);
|
||
}
|
||
|
||
// add data members recursively
|
||
addClassData(builder, cd);
|
||
|
||
// add tail padding
|
||
if (instanceSize) // can be 0 for opaque classes
|
||
builder.addTailPadding(instanceSize);
|
||
}
|
||
|
||
// set struct body and copy GEP indices
|
||
isaStruct(type)->setBody(builder.defaultTypes(), builder.isPacked());
|
||
varGEPIndices = builder.varGEPIndices();
|
||
|
||
if (!cd->isInterfaceDeclaration() && instanceSize &&
|
||
getTypeAllocSize(type) != instanceSize) {
|
||
error(cd->loc, "ICE: class IR size does not match the frontend size");
|
||
fatal();
|
||
}
|
||
|
||
IF_LOG Logger::cout() << "class type: " << *type << std::endl;
|
||
|
||
return type;
|
||
}
|
||
|
||
size_t IrTypeClass::getInterfaceIndex(ClassDeclaration *inter) {
|
||
getMemoryLLType(); // lazily resolve
|
||
|
||
auto it = interfaceMap.find(inter);
|
||
if (it == interfaceMap.end()) {
|
||
return ~0UL;
|
||
}
|
||
return it->second;
|
||
}
|
||
|
||
unsigned IrTypeClass::getNumInterfaceVtbls() {
|
||
getMemoryLLType(); // lazily resolve
|
||
return num_interface_vtbls;
|
||
}
|
||
|
||
const VarGEPIndices &IrTypeClass::getVarGEPIndices() {
|
||
getMemoryLLType(); // lazily resolve
|
||
return varGEPIndices;
|
||
}
|
||
|
||
void IrTypeClass::addInterfaceToMap(ClassDeclaration *inter, size_t index) {
|
||
// don't duplicate work or overwrite indices
|
||
if (interfaceMap.find(inter) != interfaceMap.end()) {
|
||
return;
|
||
}
|
||
|
||
// add this interface
|
||
interfaceMap.insert(std::make_pair(inter, index));
|
||
|
||
// add the direct base interfaces recursively - they
|
||
// are accessed through the same index
|
||
if (inter->interfaces.length > 0) {
|
||
BaseClass *b = inter->interfaces.ptr[0];
|
||
addInterfaceToMap(b->sym, index);
|
||
}
|
||
}
|