Mercurial > projects > ldc
diff gen/classes.cpp @ 1228:79758fd2f48a
Added Doxygen file.
Completely seperated type and symbol generation. Should fix a lot of bugs, but is not yet 100% complete.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail.com> |
---|---|
date | Wed, 15 Apr 2009 20:06:25 +0200 |
parents | 3d4581761b4c |
children | fafe7c8d6734 |
line wrap: on
line diff
--- a/gen/classes.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/classes.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -16,183 +16,10 @@ #include "gen/runtime.h" #include "gen/dvalue.h" #include "gen/nested.h" +#include "gen/utils.h" #include "ir/irstruct.h" - -////////////////////////////////////////////////////////////////////////////////////////// - -// adds the base interfaces of b and the given iri to IrStruct's interfaceMap -static void add_base_interfaces(IrStruct* to, IrInterface* iri, BaseClass* b) -{ - for (unsigned j = 0; j < b->baseInterfaces_dim; j++) - { - BaseClass *bc = &b->baseInterfaces[j]; - // add to map - if (to->interfaceMap.find(bc->base) == to->interfaceMap.end()) - { - to->interfaceMap.insert(std::make_pair(bc->base, iri)); - } - // add base interfaces - add_base_interfaces(to, iri, bc); - } -} - -// adds interface b to target, if newinstance != 0, then target must provide all -// functions required to implement b (it reimplements b) -static void add_interface(ClassDeclaration* target, BaseClass* b, int newinstance) -{ - Logger::println("adding interface: %s", b->base->toChars()); - LOG_SCOPE; - - InterfaceDeclaration* inter = b->base->isInterfaceDeclaration(); - DtoResolveClass(inter); - - assert(inter); - IrStruct* irstruct = target->ir.irStruct; - assert(irstruct); - - // add interface to map/list - // if it's already inserted in the map, it's because another interface has it as baseclass - // but if it appears here, it's because we're reimplementing it, so we overwrite the IrInterface entry - IrInterface* iri; - bool overwrite = false; - if (irstruct->interfaceMap.find(inter) != irstruct->interfaceMap.end()) - { - overwrite = true; - } - - iri = new IrInterface(b); - // add to map - if (overwrite) - irstruct->interfaceMap[b->base] = iri; - else - irstruct->interfaceMap.insert(std::make_pair(b->base, iri)); - - // add to ordered list - irstruct->interfaceVec.push_back(iri); - - // add to classinfo interfaces - if (newinstance) - irstruct->classInfoInterfaces.push_back(iri); - - // recursively assign this iri to all base interfaces - add_base_interfaces(irstruct, iri, b); - - // build the interface vtable - b->fillVtbl(target, &iri->vtblDecls, newinstance); - - // add the vtable type - assert(inter->type->ir.type); - irstruct->types.push_back( inter->type->ir.type->get() ); - // set and increment index - iri->index = irstruct->index++; -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void add_class_data(ClassDeclaration* target, ClassDeclaration* cd) -{ - Logger::println("Adding data from class: %s", cd->toChars()); - LOG_SCOPE; - - // recurse into baseClasses - if (cd->baseClass) - { - add_class_data(target, cd->baseClass); - //offset = baseClass->structsize; - } - - // add members - Array* arr = cd->members; - for (int k=0; k < arr->dim; k++) { - Dsymbol* s = (Dsymbol*)arr->data[k]; - s->codegen(Type::sir); - } - - // add interfaces - if (cd->vtblInterfaces) - { - Logger::println("num vtbl interfaces: %u", cd->vtblInterfaces->dim); - for (int i = 0; i < cd->vtblInterfaces->dim; i++) - { - BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i]; - assert(b); - // create new instances only for explicitly derived interfaces - add_interface(target, b, (cd == target)); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DtoDeclareInterface(InterfaceDeclaration* cd); -static void DtoConstInitInterface(InterfaceDeclaration* cd); -static void DtoDefineInterface(InterfaceDeclaration* cd); - -static void DtoResolveInterface(InterfaceDeclaration* cd) -{ - if (cd->ir.resolved) return; - cd->ir.resolved = true; - - Logger::println("DtoResolveInterface(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - // get the TypeClass - assert(cd->type->ty == Tclass); - TypeClass* ts = (TypeClass*)cd->type; - - // create the IrStruct, we need somewhere to store the classInfo - assert(!cd->ir.irStruct); - IrStruct* irstruct = new IrStruct(cd); - cd->ir.irStruct = irstruct; - - // create the type - const LLType* t = LLArrayType::get(getVoidPtrType(), cd->vtbl.dim); - assert(!ts->ir.type); - ts->ir.type = new LLPATypeHolder(getPtrToType(t)); - - // ... and ClassInfo - std::string varname("_D"); - varname.append(cd->mangle()); - varname.append("11__InterfaceZ"); - - // create global - irstruct->classInfo = new llvm::GlobalVariable(irstruct->classInfoOpaque.get(), false, DtoLinkage(cd), NULL, varname, gIR->module); - - // handle base interfaces - if (cd->baseclasses.dim) - { - Logger::println("num baseclasses: %u", cd->baseclasses.dim); - LOG_SCOPE; - - for (int i=0; i<cd->baseclasses.dim; i++) - { - BaseClass* bc = (BaseClass*)cd->baseclasses.data[i]; - Logger::println("baseclass %d: %s", i, bc->base->toChars()); - - InterfaceDeclaration* id = bc->base->isInterfaceDeclaration(); - assert(id); - - DtoResolveInterface(id); - - // add to interfaceInfos - IrInterface* iri = new IrInterface(bc); - irstruct->interfaceVec.push_back(iri); - irstruct->classInfoInterfaces.push_back(iri); - } - } - - // request declaration - DtoDeclareInterface(cd); - - // handle members - // like "nested" interfaces - Array* arr = cd->members; - for (int k=0; k < arr->dim; k++) { - Dsymbol* s = (Dsymbol*)arr->data[k]; - s->codegen(Type::sir); - } -} +#include "ir/irtypeclass.h" ////////////////////////////////////////////////////////////////////////////////////////// @@ -200,12 +27,6 @@ void DtoResolveClass(ClassDeclaration* cd) { - if (InterfaceDeclaration* id = cd->isInterfaceDeclaration()) - { - DtoResolveInterface(id); - return; - } - // make sure the base classes are processed first if (cd->baseClass) cd->baseClass->codegen(Type::sir); @@ -216,722 +37,61 @@ Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; - // get the TypeClass - assert(cd->type->ty == Tclass); - TypeClass* ts = (TypeClass*)cd->type; + // make sure type exists + DtoType(cd->type); - // create the IrStruct - assert(!cd->ir.irStruct); + // create IrStruct + assert(cd->ir.irStruct == NULL); IrStruct* irstruct = new IrStruct(cd); cd->ir.irStruct = irstruct; - // create the type - ts->ir.type = new LLPATypeHolder(llvm::OpaqueType::get()); - - // if it just a forward declaration? - if (cd->sizeok != 1) - { - // just name the type - gIR->module->addTypeName(cd->mangle(), ts->ir.type->get()); - return; - } - - // create the symbols we're going to need - // avoids chicken egg problems - llvm::GlobalValue::LinkageTypes _linkage = DtoLinkage(cd); - - // there is always a vtbl symbol - std::string varname("_D"); - varname.append(cd->mangle()); - varname.append("6__vtblZ"); - irstruct->vtbl = new llvm::GlobalVariable(irstruct->vtblInitTy.get(), true, _linkage, NULL, varname, gIR->module); - - // ... and initZ - varname = "_D"; - varname.append(cd->mangle()); - varname.append("6__initZ"); - irstruct->init = new llvm::GlobalVariable(irstruct->initOpaque.get(), true, _linkage, NULL, varname, gIR->module); - - // ... and ClassInfo - varname = "_D"; - varname.append(cd->mangle()); - varname.append("7__ClassZ"); - - // create global - irstruct->classInfo = new llvm::GlobalVariable(irstruct->classInfoOpaque.get(), false, _linkage, NULL, varname, gIR->module); - - // push state - gIR->structs.push_back(irstruct); - - // add vtable - irstruct->types.push_back(getPtrToType(irstruct->vtblTy.get())); - irstruct->index++; - - // add monitor - irstruct->types.push_back(getVoidPtrType()); - irstruct->index++; - - // add class data fields and interface vtables recursively - add_class_data(cd, cd); - - // check if errors occured while building interface vtables - if (global.errors) - fatal(); - - // create type - assert(irstruct->index == irstruct->types.size()); - const LLType* structtype = irstruct->build(); - - // refine abstract types for stuff like: class C {C next;} - llvm::PATypeHolder* spa = ts->ir.type; - llvm::cast<llvm::OpaqueType>(spa->get())->refineAbstractTypeTo(structtype); - structtype = isaStruct(spa->get()); - assert(structtype); - - // name the type - gIR->module->addTypeName(cd->mangle(), ts->ir.type->get()); - - // refine vtable type + bool needs_def = mustDefineSymbol(cd); - // void*[vtbl.dim] - llvm::cast<llvm::OpaqueType>(irstruct->vtblTy.get())->refineAbstractTypeTo(LLArrayType::get(getVoidPtrType(), cd->vtbl.dim)); - - // log -// if (Logger::enabled()) -// Logger::cout() << "final class type: " << *ts->ir.type->get() << '\n'; - - // pop state - gIR->structs.pop_back(); - - // queue declare - DtoDeclareClass(cd); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DtoDeclareInterface(InterfaceDeclaration* cd) -{ - DtoResolveInterface(cd); - - if (cd->ir.declared) return; - cd->ir.declared = true; - - Logger::println("DtoDeclareInterface(%s): %s", cd->toPrettyChars(), cd->locToChars()); - LOG_SCOPE; - - assert(cd->ir.irStruct); - IrStruct* irstruct = cd->ir.irStruct; - - // get interface info type - const llvm::StructType* infoTy = DtoInterfaceInfoType(); + // emit the ClassZ symbol + LLGlobalVariable* ClassZ = irstruct->getClassInfoSymbol(); - // interface info array - if (!irstruct->interfaceVec.empty()) { - // symbol name - std::string nam = "_D"; - nam.append(cd->mangle()); - nam.append("16__interfaceInfosZ"); - - llvm::GlobalValue::LinkageTypes linkage = DtoLinkage(cd); - - // resolve array type - const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, irstruct->interfaceVec.size()); - // declare global - irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, linkage, NULL, nam, gIR->module); - - // do each interface info - unsigned idx = 0; - size_t n = irstruct->interfaceVec.size(); - for (size_t i=0; i < n; i++) - { - IrInterface* iri = irstruct->interfaceVec[i]; - ClassDeclaration* id = iri->decl; - - // always create interfaceinfos - LLConstant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)}; - iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2); - idx++; - } - } - - // declare the classinfo - DtoDeclareClassInfo(cd); - - // request const init - DtoConstInitInterface(cd); - - // emit typeinfo and request definition - if (mustDefineSymbol(cd)) + // interface only emit typeinfo and classinfo + if (!cd->isInterfaceDeclaration()) { - DtoDefineInterface(cd); - DtoTypeInfoOf(cd->type, false); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - -// FIXME: this needs to be cleaned up - -void DtoDeclareClass(ClassDeclaration* cd) -{ - if (InterfaceDeclaration* id = cd->isInterfaceDeclaration()) - { - DtoDeclareInterface(id); - return; - } - - DtoResolveClass(cd); - - if (cd->ir.declared) return; - cd->ir.declared = true; - - Logger::println("DtoDeclareClass(%s): %s", cd->toPrettyChars(), cd->locToChars()); - LOG_SCOPE; - - //printf("declare class: %s\n", cd->toPrettyChars()); - - assert(cd->type->ty == Tclass); - TypeClass* ts = (TypeClass*)cd->type; - - assert(cd->ir.irStruct); - IrStruct* irstruct = cd->ir.irStruct; + // emit the initZ symbol + LLGlobalVariable* initZ = irstruct->getInitSymbol(); + // emit the vtblZ symbol + LLGlobalVariable* vtblZ = irstruct->getVtblSymbol(); - gIR->structs.push_back(irstruct); - - bool needs_definition = false; - if (mustDefineSymbol(cd)) { - needs_definition = true; - } - - llvm::GlobalValue::LinkageTypes _linkage = DtoLinkage(cd); - - // get interface info type - const llvm::StructType* infoTy = DtoInterfaceInfoType(); - - // interface info array - if (!irstruct->interfaceVec.empty()) { - // symbol name - std::string nam = "_D"; - nam.append(cd->mangle()); - nam.append("16__interfaceInfosZ"); - // resolve array type - const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, irstruct->interfaceVec.size()); - // declare global - irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, _linkage, NULL, nam, gIR->module); - } - - // DMD gives abstract classes a full ClassInfo, so we do it as well - - // interface vtables - unsigned idx = 0; - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) - { - IrInterface* iri = *i; - ClassDeclaration* id = iri->decl; + // emit the interfaceInfosZ symbol if necessary + if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) + getInterfaceArraySymbol(); // initializer is applied when it's built - std::string nam("_D"); - nam.append(cd->mangle()); - nam.append("11__interface"); - nam.append(id->mangle()); - nam.append("6__vtblZ"); - - iri->vtbl = new llvm::GlobalVariable(iri->vtblInitTy.get(), true, _linkage, 0, nam, gIR->module); - - // always set the interface info as it's need as the first vtbl entry - LLConstant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)}; - iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2); - idx++; - } - - gIR->structs.pop_back(); - - // request const init - DtoConstInitClass(cd); - - // define ? (set initializers) - if (needs_definition) - DtoDefineClass(cd); - - // classinfo - DtoDeclareClassInfo(cd); - - // do typeinfo ? - if (needs_definition) - DtoTypeInfoOf(cd->type, false); -} - -////////////////////////////////////////////////////////////////////////////// + // perform definition + if (needs_def) + { + // set symbol initializers + initZ->setInitializer(irstruct->getDefaultInit()); + vtblZ->setInitializer(irstruct->getVtblInit()); + } -// adds data fields and interface vtables to the constant initializer of class cd -static size_t init_class_initializer(std::vector<LLConstant*>& inits, ClassDeclaration* target, ClassDeclaration* cd, size_t offsetbegin) -{ - // first do baseclasses - if (cd->baseClass) - { - offsetbegin = init_class_initializer(inits, target, cd->baseClass, offsetbegin); - } - - Logger::println("adding data of %s to %s starting at %lu", cd->toChars(), target->toChars(), offsetbegin); - LOG_SCOPE; - - // add default fields - VarDeclaration** fields = (VarDeclaration**)cd->fields.data; - size_t nfields = cd->fields.dim; - - std::vector<VarDeclaration*> defVars; - defVars.reserve(nfields); - - size_t lastoffset = offsetbegin; - size_t lastsize = 0; - - // find fields that contribute to default - for (size_t i=0; i<nfields; i++) - { - VarDeclaration* var = fields[i]; - // only add vars that don't overlap - size_t offset = var->offset; - size_t size = var->type->size(); - if (offset >= lastoffset+lastsize) + // emit members + if (cd->members) { - Logger::println(" added %s", var->toChars()); - lastoffset = offset; - lastsize = size; - defVars.push_back(var); - } - else - { - Logger::println(" skipped %s at offset %u, current pos is %lu", var->toChars(), var->offset, lastoffset+lastsize); + ArrayIter<Dsymbol> it(*cd->members); + while (!it.done()) + { + Dsymbol* member = it.get(); + if (member) + member->codegen(Type::sir); + it.next(); + } } } - // reset offsets, we're going from beginning again - lastoffset = offsetbegin; - lastsize = 0; - - // go through the default vars and build the default constant initializer - // adding zeros along the way to live up to alignment expectations - size_t nvars = defVars.size(); - for (size_t i=0; i<nvars; i++) - { - VarDeclaration* var = defVars[i]; - - Logger::println("field %s %s = %s : +%u", var->type->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset); - - // get offset and size - size_t offset = var->offset; - size_t size = var->type->size(); - - // is there space in between last last offset and this one? - // if so, fill it with zeros - if (offset > lastoffset+lastsize) - { - size_t pos = lastoffset + lastsize; - addZeros(inits, pos, offset); - } - - // add the field - // and build its constant initializer lazily - if (!var->ir.irField->constInit) - var->ir.irField->constInit = DtoConstInitializer(var->loc, var->type, var->init); - inits.push_back(var->ir.irField->constInit); - - lastoffset = offset; - lastsize = var->type->size(); - } - - // if it's a class, and it implements interfaces, add the vtables - as found in the target class! - IrStruct* irstruct = target->ir.irStruct; - - size_t nvtbls = cd->vtblInterfaces->dim; - for(size_t i=0; i<nvtbls; i++) - { - BaseClass* bc = (BaseClass*)cd->vtblInterfaces->data[i]; - IrStruct::InterfaceMap::iterator iter = irstruct->interfaceMap.find(bc->base); - assert(iter != irstruct->interfaceMap.end()); - - IrInterface* iri = iter->second; - if (iri->vtbl) - inits.push_back(iri->vtbl); - else // abstract impl - inits.push_back(getNullPtr(getVoidPtrType())); - - lastoffset += lastsize; - lastsize = PTRSIZE; - } - - // return next offset - return lastoffset + lastsize; -} - -////////////////////////////////////////////////////////////////////////////// - -// build the vtable initializer for class cd -static void init_class_vtbl_initializer(ClassDeclaration* cd) -{ - cd->codegen(Type::sir); - - // generate vtable initializer - std::vector<LLConstant*> sinits(cd->vtbl.dim, NULL); - - IrStruct* irstruct = cd->ir.irStruct; - - assert(cd->vtbl.dim > 1); - - DtoDeclareClassInfo(cd); - - // first entry always classinfo - assert(irstruct->classInfo); - sinits[0] = DtoBitCast(irstruct->classInfo, DtoType(ClassDeclaration::classinfo->type)); - - // add virtual functions - for (int k=1; k < cd->vtbl.dim; k++) - { - Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k]; - assert(dsym); - -// Logger::println("vtbl[%d] = %s", k, dsym->toChars()); - - FuncDeclaration* fd = dsym->isFuncDeclaration(); - assert(fd); - - // if function is abstract, - // or class is abstract, and func has no body, - // emit a null vtbl entry - if (fd->isAbstract() || (cd->isAbstract() && !fd->fbody)) - { - sinits[k] = getNullPtr(getVoidPtrType()); - } - else - { - fd->codegen(Type::sir); - Logger::println("F = %s", fd->toPrettyChars()); - assert(fd->ir.irFunc); - assert(fd->ir.irFunc->func); - sinits[k] = fd->ir.irFunc->func; - } - -// if (Logger::enabled()) -// Logger::cout() << "vtbl[" << k << "] = " << *sinits[k] << std::endl; - } - - irstruct->constVtbl = LLConstantStruct::get(sinits); - - // refine type - llvm::cast<llvm::OpaqueType>(irstruct->vtblInitTy.get())->refineAbstractTypeTo(irstruct->constVtbl->getType()); - -// if (Logger::enabled()) -// Logger::cout() << "vtbl initializer: " << *irstruct->constVtbl << std::endl; -} - -////////////////////////////////////////////////////////////////////////////// - -static void init_class_interface_vtbl_initializers(ClassDeclaration* cd) -{ - IrStruct* irstruct = cd->ir.irStruct; - - // don't do anything if list is empty - if (irstruct->interfaceVec.empty()) - return; - - std::vector<LLConstant*> inits; - std::vector<LLConstant*> infoInits(3); - - // go through each interface - size_t ninter = irstruct->interfaceVec.size(); - for (size_t i=0; i<ninter; i++) - { - IrInterface* iri = irstruct->interfaceVec[i]; - Logger::println("interface %s", iri->decl->toChars()); - - // build vtable intializer for this interface implementation - Array& arr = iri->vtblDecls; - size_t narr = arr.dim; - - if (narr > 0) - { - inits.resize(narr, NULL); - - // first is always the interface info - assert(iri->info); - inits[0] = iri->info; - - // build vtable - for (size_t j=1; j < narr; j++) - { - Dsymbol* dsym = (Dsymbol*)arr.data[j]; - if (!dsym) - { - inits[j] = getNullPtr(getVoidPtrType()); - continue; - } - - //Logger::println("ivtbl[%d] = %s", j, dsym->toChars()); - - // must all be functions - FuncDeclaration* fd = dsym->isFuncDeclaration(); - assert(fd); - - if (fd->isAbstract()) - inits[j] = getNullPtr(getVoidPtrType()); - else - { - fd->codegen(Type::sir); - - assert(fd->ir.irFunc->func); - inits[j] = fd->ir.irFunc->func; - } - - //if (Logger::enabled()) - // Logger::cout() << "ivtbl[" << j << "] = " << *inits[j] << std::endl; - } - - // build the constant - iri->vtblInit = LLConstantStruct::get(inits); - } - - // build the interface info for ClassInfo - // generate interface info initializer - - iri->decl->codegen(Type::sir); - - // classinfo - IrStruct* iris = iri->decl->ir.irStruct; - assert(iris); - assert(iris->classInfo); - infoInits[0] = DtoBitCast(iris->classInfo, DtoType(ClassDeclaration::classinfo->type)); - - // vtbl - LLConstant* c; - if (iri->vtbl) - c = llvm::ConstantExpr::getBitCast(iri->vtbl, getPtrToType(getVoidPtrType())); - else - c = getNullPtr(getPtrToType(getVoidPtrType())); - infoInits[1] = DtoConstSlice(DtoConstSize_t(narr), c); - - // offset - size_t ioff; - if (iri->index == 0) - ioff = 0; - else - ioff = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(iri->index); + // emit typeinfo + DtoTypeInfoOf(cd->type); - Logger::println("DMD interface offset: %d, LLVM interface offset: %lu", iri->base->offset, ioff); - assert(iri->base->offset == ioff); - infoInits[2] = DtoConstUint(ioff); - - // create interface info initializer constant - iri->infoInit = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(infoInits)); - } -} - -////////////////////////////////////////////////////////////////////////////// - -static void DtoConstInitInterface(InterfaceDeclaration* cd) -{ - DtoDeclareInterface(cd); - - if (cd->ir.initialized) return; - cd->ir.initialized = true; - - Logger::println("DtoConstInitClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - init_class_interface_vtbl_initializers(cd); -} - -////////////////////////////////////////////////////////////////////////////// - -void DtoConstInitClass(ClassDeclaration* cd) -{ - if (InterfaceDeclaration* it = cd->isInterfaceDeclaration()) + // define classinfo + if (needs_def) { - DtoConstInitInterface(it); - return; - } - - DtoDeclareClass(cd); - - if (cd->ir.initialized) return; - cd->ir.initialized = true; - - Logger::println("DtoConstInitClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - // get IrStruct - IrStruct* irstruct = cd->ir.irStruct; - gIR->structs.push_back(irstruct); - - // get types - TypeClass* tc = (TypeClass*)cd->type; - const llvm::StructType* structtype = isaStruct(tc->ir.type->get()); - assert(structtype); - const llvm::ArrayType* vtbltype = isaArray(irstruct->vtblTy.get()); - assert(vtbltype); - - // build initializer list - std::vector<LLConstant*> inits; - inits.reserve(irstruct->varDecls.size()); - - // vtable is always first - assert(irstruct->vtbl != 0); - inits.push_back(irstruct->vtbl); - - // then comes monitor - inits.push_back(LLConstant::getNullValue(getVoidPtrType())); - - // recursively do data and interface vtables - init_class_initializer(inits, cd, cd, 2 * PTRSIZE); - - // build vtable initializer - init_class_vtbl_initializer(cd); - - // build interface vtables - init_class_interface_vtbl_initializers(cd); - - // build constant from inits - assert(!irstruct->constInit); - irstruct->constInit = LLConstantStruct::get(inits); // classes are never packed - - // refine __initZ global type to the one of the initializer - llvm::cast<llvm::OpaqueType>(irstruct->initOpaque.get())->refineAbstractTypeTo(irstruct->constInit->getType()); - - // build initializers for static member variables - size_t n = irstruct->staticVars.size(); - for (size_t i = 0; i < n; ++i) - { - DtoConstInitGlobal(irstruct->staticVars[i]); + ClassZ->setInitializer(irstruct->getClassInfoInit()); } - // This is all we use it for. Clear the memory! - irstruct->staticVars.clear(); - -// if (Logger::enabled()) -// { -// Logger::cout() << "class " << cd->toChars() << std::endl; -// Logger::cout() << "type " << *cd->type->ir.type->get() << std::endl; -// Logger::cout() << "initializer " << *irstruct->constInit << std::endl; -// } - - gIR->structs.pop_back(); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DefineInterfaceInfos(IrStruct* irstruct) -{ - // always do interface info array when possible - std::vector<LLConstant*> infoInits; - - size_t n = irstruct->interfaceVec.size(); - infoInits.reserve(n); - - for (size_t i=0; i < n; i++) - { - IrInterface* iri = irstruct->interfaceVec[i]; - assert(iri->infoInit); - infoInits.push_back(iri->infoInit); - } - - // set initializer - if (!infoInits.empty()) - { - const LLArrayType* arrty = LLArrayType::get(infoInits[0]->getType(), infoInits.size()); - LLConstant* arrInit = llvm::ConstantArray::get(arrty, infoInits); - irstruct->interfaceInfos->setInitializer(arrInit); - } - else - { - assert(irstruct->interfaceInfos == NULL); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DtoDefineInterface(InterfaceDeclaration* cd) -{ - DtoConstInitInterface(cd); - - if (cd->ir.defined) return; - cd->ir.defined = true; - - Logger::println("DtoDefineClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - // defined interface infos - DefineInterfaceInfos(cd->ir.irStruct); - - // define the classinfo - if (mustDefineSymbol(cd)) - { - DtoDefineClassInfo(cd); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - -// FIXME: clean this up - -void DtoDefineClass(ClassDeclaration* cd) -{ - if (InterfaceDeclaration* id = cd->isInterfaceDeclaration()) - { - DtoDefineInterface(id); - return; - } - - DtoConstInitClass(cd); - - if (cd->ir.defined) return; - cd->ir.defined = true; - - Logger::println("DtoDefineClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - // get the struct (class) type - assert(cd->type->ty == Tclass); - TypeClass* ts = (TypeClass*)cd->type; - - IrStruct* irstruct = cd->ir.irStruct; - - assert(mustDefineSymbol(cd)); - - // sanity check - assert(irstruct->init); - assert(irstruct->constInit); - assert(irstruct->vtbl); - assert(irstruct->constVtbl); - -// if (Logger::enabled()) -// { -// Logger::cout() << "initZ: " << *irstruct->init << std::endl; -// Logger::cout() << "cinitZ: " << *irstruct->constInit << std::endl; -// Logger::cout() << "vtblZ: " << *irstruct->vtbl << std::endl; -// Logger::cout() << "cvtblZ: " << *irstruct->constVtbl << std::endl; -// } - - // set initializers - irstruct->init->setInitializer(irstruct->constInit); - irstruct->vtbl->setInitializer(irstruct->constVtbl); - - // initialize interface vtables - size_t n = irstruct->interfaceVec.size(); - for (size_t i=0; i<n; i++) - { - IrInterface* iri = irstruct->interfaceVec[i]; - Logger::println("interface %s", iri->base->base->toChars()); - assert(iri->vtblInit); - - // refine the init type - llvm::cast<llvm::OpaqueType>(iri->vtblInitTy.get())->refineAbstractTypeTo(iri->vtblInit->getType()); - - // apply initializer - assert(iri->vtbl); - iri->vtbl->setInitializer(iri->vtblInit); - } - - DefineInterfaceInfos(irstruct); - - // generate classinfo - DtoDefineClassInfo(cd); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -959,7 +119,7 @@ else { llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_allocclass"); - LLConstant* ci = DtoBitCast(tc->sym->ir.irStruct->classInfo, DtoType(ClassDeclaration::classinfo->type)); + LLConstant* ci = DtoBitCast(tc->sym->ir.irStruct->getClassInfoSymbol(), DtoType(ClassDeclaration::classinfo->type)); mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction(); mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc"); } @@ -1019,9 +179,8 @@ uint64_t n = getTypePaddedSize(tc->ir.type->get()) - presz; // set vtable field seperately, this might give better optimization - assert(tc->sym->ir.irStruct->vtbl); LLValue* tmp = DtoGEPi(dst,0,0,"vtbl"); - LLValue* val = DtoBitCast(tc->sym->ir.irStruct->vtbl, tmp->getType()->getContainedType(0)); + LLValue* val = DtoBitCast(tc->sym->ir.irStruct->getVtblSymbol(), tmp->getType()->getContainedType(0)); DtoStore(val, tmp); // monitor always defaults to zero @@ -1034,10 +193,8 @@ return; // copy the rest from the static initializer - assert(tc->sym->ir.irStruct->init); - LLValue* dstarr = DtoGEPi(dst,0,2,"tmp"); - LLValue* srcarr = DtoGEPi(tc->sym->ir.irStruct->init,0,2,"tmp"); + LLValue* srcarr = DtoGEPi(tc->sym->ir.irStruct->getInitSymbol(),0,2,"tmp"); DtoMemCpy(dstarr, srcarr, DtoConstSize_t(n)); } @@ -1098,18 +255,22 @@ // class -> interface - static cast else if (it->isBaseOf(fc->sym,NULL)) { Logger::println("static down cast"); + // get the from class ClassDeclaration* cd = fc->sym->isClassDeclaration(); DtoResolveClass(cd); // add this IrStruct* irstruct = cd->ir.irStruct; + IrTypeClass* typeclass = fc->irtype->isClass(); + // find interface impl - IrStruct::InterfaceMapIter iriter = irstruct->interfaceMap.find(it); - assert(iriter != irstruct->interfaceMap.end()); - IrInterface* iri = iriter->second; + + size_t i_index = typeclass->getInterfaceIndex(it); + assert(i_index != ~0 && "requesting interface that is not implemented by this class"); + // offset pointer LLValue* v = val->getRVal(); LLValue* orig = v; - v = DtoGEPi(v, 0, iri->index); + v = DtoGEPi(v, 0, i_index); const LLType* ifType = DtoType(_to); if (Logger::enabled()) { @@ -1117,12 +278,14 @@ Logger::cout() << "T = " << *ifType << std::endl; } v = DtoBitCast(v, ifType); + // Check whether the original value was null, and return null if so. // Sure we could have jumped over the code above in this case, but // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it // should be pretty cheap and perfectly safe even if the original was null. LLValue* isNull = gIR->ir->CreateICmpEQ(orig, LLConstant::getNullValue(orig->getType()), ".nullcheck"); v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(ifType), v, ".interface"); + // return r-value return new DImValue(_to, v); } @@ -1179,8 +342,8 @@ // ClassInfo c TypeClass* to = (TypeClass*)_to->toBasetype(); to->sym->codegen(Type::sir); - assert(to->sym->ir.irStruct->classInfo); - LLValue* cinfo = to->sym->ir.irStruct->classInfo; + + LLValue* cinfo = to->sym->ir.irStruct->getClassInfoSymbol(); // unfortunately this is needed as the implementation of object differs somehow from the declaration // this could happen in user code as well :/ cinfo = DtoBitCast(cinfo, funcTy->getParamType(1)); @@ -1243,8 +406,7 @@ // ClassInfo c TypeClass* to = (TypeClass*)_to->toBasetype(); to->sym->codegen(Type::sir); - assert(to->sym->ir.irStruct->classInfo); - LLValue* cinfo = to->sym->ir.irStruct->classInfo; + LLValue* cinfo = to->sym->ir.irStruct->getClassInfoSymbol(); // unfortunately this is needed as the implementation of object differs somehow from the declaration // this could happen in user code as well :/ cinfo = DtoBitCast(cinfo, funcTy->getParamType(1)); @@ -1346,23 +508,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -void DtoDeclareClassInfo(ClassDeclaration* cd) -{ - IrStruct* irstruct = cd->ir.irStruct; - - if (irstruct->classInfoDeclared) return; - irstruct->classInfoDeclared = true; - - Logger::println("DtoDeclareClassInfo(%s)", cd->toChars()); - LOG_SCOPE; - - // resovle ClassInfo - ClassDeclaration* cinfo = ClassDeclaration::classinfo; - DtoResolveClass(cinfo); -} - -////////////////////////////////////////////////////////////////////////////////////////// - #if GENERATE_OFFTI // build a single element for the OffsetInfo[] of ClassInfo @@ -1467,7 +612,7 @@ return flags; } -void DtoDefineClassInfo(ClassDeclaration* cd) +LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) { // The layout is: // { @@ -1486,25 +631,14 @@ // void *defaultConstructor; // } - IrStruct* ir = cd->ir.irStruct; - - if (ir->classInfoDefined) return; - ir->classInfoDefined = true; - Logger::println("DtoDefineClassInfo(%s)", cd->toChars()); LOG_SCOPE; + IrStruct* ir = cd->ir.irStruct; + assert(cd->type->ty == Tclass); - assert(ir->classInfo); TypeClass* cdty = (TypeClass*)cd->type; - if (!cd->isInterfaceDeclaration()) - { - assert(ir->init); - assert(ir->constInit); - assert(ir->vtbl); - assert(ir->constVtbl); - } // holds the list of initializers for llvm std::vector<LLConstant*> inits; @@ -1518,8 +652,7 @@ const LLType* voidPtrPtr = getPtrToType(voidPtr); // own vtable - c = cinfo->ir.irStruct->vtbl; - assert(c); + c = cinfo->ir.irStruct->getVtblSymbol(); inits.push_back(c); // monitor @@ -1531,9 +664,9 @@ c = DtoConstSlice(DtoConstSize_t(0), LLConstant::getNullValue(voidPtr)); else { - c = DtoBitCast(ir->init, voidPtr); + c = DtoBitCast(ir->getInitSymbol(), voidPtr); //Logger::cout() << *ir->constInit->getType() << std::endl; - size_t initsz = getTypePaddedSize(ir->init->getType()->getContainedType(0)); + size_t initsz = getTypePaddedSize(ir->getInitSymbol()->getType()->getContainedType(0)); c = DtoConstSlice(DtoConstSize_t(initsz), c); } inits.push_back(c); @@ -1554,36 +687,19 @@ if (cd->isInterfaceDeclaration()) c = DtoConstSlice(DtoConstSize_t(0), LLConstant::getNullValue(getPtrToType(voidPtr))); else { - c = DtoBitCast(ir->vtbl, voidPtrPtr); + c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr); c = DtoConstSlice(DtoConstSize_t(cd->vtbl.dim), c); } inits.push_back(c); // interfaces array - VarDeclaration* intersVar = (VarDeclaration*)cinfo->fields.data[3]; - const LLType* intersTy = DtoType(intersVar->type); - if (!ir->interfaceInfos) - c = LLConstant::getNullValue(intersTy); - else { - const LLType* t = intersTy->getContainedType(1); // .ptr - // cast to Interface* - c = DtoBitCast(ir->interfaceInfos, t); - size_t isz = ir->interfaceVec.size(); - size_t iisz = ir->classInfoInterfaces.size(); - assert(iisz <= isz); - // offset - we only want the 'iisz' last ones - LLConstant* idx = DtoConstUint(isz - iisz); - c = llvm::ConstantExpr::getGetElementPtr(c, &idx, 1); - // make array - c = DtoConstSlice(DtoConstSize_t(iisz), c); - } + c = ir->getClassInfoInterfaces(); inits.push_back(c); // base classinfo // interfaces never get a base , just the interfaces[] if (cd->baseClass && !cd->isInterfaceDeclaration()) { - DtoDeclareClassInfo(cd->baseClass); - c = cd->baseClass->ir.irStruct->classInfo; + c = cd->baseClass->ir.irStruct->getClassInfoSymbol(); assert(c); inits.push_back(c); } @@ -1684,9 +800,11 @@ //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; ir->constClassInfo = finalinit; - // refine the type - llvm::cast<llvm::OpaqueType>(ir->classInfoOpaque.get())->refineAbstractTypeTo(finalinit->getType()); + // sanity check + assert(finalinit->getType() == ir->classInfo->getType()->getContainedType(0) && + "__ClassZ initializer does not match the ClassInfo type"); + - // apply initializer - ir->classInfo->setInitializer(finalinit); + // return initializer + return finalinit; }