# HG changeset patch # User lindquist # Date 1195882380 -3600 # Node ID 27b9f749d9fe4a55012f4027141875423321d4d9 # Parent 368547b1cbe6d9e3f14e0e7e2aeb2c6a867c1310 [svn r117] Initial working implementation of interfaces. Groundwork for all the different types of class/interface casts laid out. diff -r 368547b1cbe6 -r 27b9f749d9fe gen/classes.cpp --- a/gen/classes.cpp Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/classes.cpp Sat Nov 24 06:33:00 2007 +0100 @@ -1,3 +1,4 @@ +#include #include "gen/llvm.h" #include "mtype.h" @@ -11,6 +12,8 @@ #include "gen/logger.h" #include "gen/classes.h" #include "gen/functions.h" +#include "gen/runtime.h" +#include "gen/dvalue.h" ////////////////////////////////////////////////////////////////////////////////////////// @@ -21,10 +24,14 @@ { BaseClass* bc = (BaseClass*)(bcs->data[j]); assert(bc); + if (bc->base->isInterfaceDeclaration()) + continue; // interfaces only has methods + + LLVM_AddBaseClassData(&bc->base->baseclasses); + Logger::println("Adding base class members of %s", bc->base->toChars()); LOG_SCOPE; - LLVM_AddBaseClassData(&bc->base->baseclasses); for (int k=0; k < bc->base->members->dim; k++) { Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]); if (dsym->isVarDeclaration()) @@ -46,10 +53,17 @@ if (cd->baseClass) { DtoResolveClass(cd->baseClass); } - // resolve typeinfo - //DtoResolveClass(ClassDeclaration::typeinfo); - // resolve classinfo - //DtoResolveClass(ClassDeclaration::classinfo); + + // resolve interfaces + if (cd->vtblInterfaces) { + for (int i=0; i < cd->vtblInterfaces->dim; i++) { + BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i]; + ClassDeclaration *id = b->base; + DtoResolveClass(id); + // Fill in vtbl[] + b->fillVtbl(cd, &b->vtbl, 1); + } + } Logger::println("DtoResolveClass(%s)", cd->toPrettyChars()); LOG_SCOPE; @@ -71,6 +85,22 @@ std::vector fieldtypes; fieldtypes.push_back(vtabty); + // add interface vtables + if (cd->vtblInterfaces) + for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) + { + BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i]; + ClassDeclaration *id = b->base; + assert(id->type->ty == Tclass); + TypeClass* itc = (TypeClass*)id->type; + const llvm::Type* ivtblTy = llvm::PointerType::get(itc->llvmVtblType->get()); + fieldtypes.push_back(ivtblTy); + + // add this interface to the map + IRInterface* iri = new IRInterface(b, isaStruct(itc->llvmVtblType->get())); + irstruct->interfaces.insert(std::make_pair(id, iri)); + } + // base classes first LLVM_AddBaseClassData(&cd->baseclasses); @@ -98,16 +128,31 @@ else *ts->llvmType = structtype; - bool needs_definition = false; if (cd->parent->isModule()) { gIR->module->addTypeName(cd->mangle(), ts->llvmType->get()); - needs_definition = (cd->getModule() == gIR->dmodule); } else { assert(0 && "class parent is not a module"); } - // generate vtable + // build interface info type + std::vector infoTypes; + // ClassInfo classinfo + ClassDeclaration* cinfod = ClassDeclaration::classinfo; + DtoResolveClass(cinfod); + infoTypes.push_back(llvm::PointerType::get(cinfod->type->llvmType->get())); + // void*[] vtbl + std::vector infoVtbltypes; + infoVtbltypes.push_back(DtoSize_t()); + const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty)); + infoVtbltypes.push_back(byteptrptrty); + infoTypes.push_back(llvm::StructType::get(infoVtbltypes)); + // int offset + infoTypes.push_back(llvm::Type::Int32Ty); + // create type + const llvm::StructType* infoTy = llvm::StructType::get(infoTypes); + + // create vtable type llvm::GlobalVariable* svtblVar = 0; std::vector sinits_ty; @@ -124,18 +169,21 @@ const llvm::Type* fpty = llvm::PointerType::get(tf->llvmType->get()); sinits_ty.push_back(fpty); } - else if (ClassDeclaration* cd = dsym->isClassDeclaration()) { - //Logger::println("*** ClassDeclaration in vtable: %s", cd->toChars()); + else if (ClassDeclaration* cd2 = dsym->isClassDeclaration()) { + Logger::println("*** ClassDeclaration in vtable: %s", cd2->toChars()); const llvm::Type* cinfoty; - if (cd != ClassDeclaration::classinfo) { - cd = ClassDeclaration::classinfo; - DtoResolveClass(cd); - cinfoty = cd->type->llvmType->get(); + if (cd->isInterfaceDeclaration()) { + cinfoty = infoTy; + } + else if (cd != cinfod) { + DtoResolveClass(cinfod); + cinfoty = cinfod->type->llvmType->get(); } else { + // this is the ClassInfo class, the type is this type cinfoty = ts->llvmType->get(); } - const llvm::Type* cty = llvm::PointerType::get(cd->type->llvmType->get()); + const llvm::Type* cty = llvm::PointerType::get(cinfoty); sinits_ty.push_back(cty); } else @@ -182,26 +230,78 @@ needs_definition = (cd->getModule() == gIR->dmodule); } - // vtable - std::string varname("_D"); - varname.append(cd->mangle()); - varname.append("6__vtblZ"); + // interface vtables are emitted by the class implementing them + // also interfaces have no static initializer + if (!cd->isInterfaceDeclaration()) { + // vtable + std::string varname("_D"); + varname.append(cd->mangle()); + varname.append("6__vtblZ"); + + llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; + + const llvm::StructType* svtbl_ty = isaStruct(ts->llvmVtblType->get()); + cd->llvmVtbl = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module); - std::string styname(cd->mangle()); - styname.append("__vtblTy"); - - llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; + // build interface info type + std::vector types; + // ClassInfo classinfo + ClassDeclaration* cd2 = ClassDeclaration::classinfo; + DtoResolveClass(cd2); + types.push_back(llvm::PointerType::get(cd2->type->llvmType->get())); + // void*[] vtbl + std::vector vtbltypes; + vtbltypes.push_back(DtoSize_t()); + const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty)); + vtbltypes.push_back(byteptrptrty); + types.push_back(llvm::StructType::get(vtbltypes)); + // int offset + types.push_back(llvm::Type::Int32Ty); + // create type + const llvm::StructType* infoTy = llvm::StructType::get(types); - const llvm::StructType* svtbl_ty = isaStruct(ts->llvmVtblType->get()); - cd->llvmVtbl = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module); + // interface info array + if (needs_definition && cd->vtblInterfaces->dim > 0) { + // 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, cd->vtblInterfaces->dim); + // declare global + irstruct->interfaceInfosTy = arrTy; + irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, llvm::GlobalValue::InternalLinkage, 0, nam, gIR->module); + } + + // interface vtables + unsigned idx = 0; + for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) + { + ClassDeclaration* id = i->first; + IRInterface* iri = i->second; - // init - std::string initname("_D"); - initname.append(cd->mangle()); - initname.append("6__initZ"); + std::string nam("_D"); + nam.append(cd->mangle()); + nam.append("11__interface"); + nam.append(id->mangle()); + nam.append("6__vtblZ"); - llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module); - ts->llvmInit = initvar; + assert(iri->vtblTy); + iri->vtbl = new llvm::GlobalVariable(iri->vtblTy, true, _linkage, 0, nam, gIR->module); + iri->infoTy = infoTy; + llvm::Constant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)}; + iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2); + idx++; + } + + // init + std::string initname("_D"); + initname.append(cd->mangle()); + initname.append("6__initZ"); + + llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module); + ts->llvmInit = initvar; + } gIR->classes.pop_back(); gIR->structs.pop_back(); @@ -225,6 +325,9 @@ if (cd->llvmInitialized) return; cd->llvmInitialized = true; + if (cd->isInterfaceDeclaration()) + return; // nothing to do + Logger::println("DtoConstInitClass(%s)", cd->toPrettyChars()); LOG_SCOPE; @@ -248,6 +351,14 @@ assert(cd->llvmVtbl != 0); fieldinits.push_back(cd->llvmVtbl); + // next comes interface vtables + for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) + { + IRInterface* iri = i->second; + assert(iri->vtbl); + fieldinits.push_back(iri->vtbl); + } + // rest for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { Logger::println("adding fieldinit for: %s", i->second.var->toChars()); @@ -260,7 +371,8 @@ const llvm::StructType* structtype = isaStruct(ts->llvmType->get()); // generate initializer - /*Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n'; +#if 0 + Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n'; for(size_t i=0; igetNumElements(); ++i) { Logger::cout() << "s#" << i << " = " << *structtype->getElementType(i) << '\n'; @@ -268,7 +380,8 @@ for(size_t i=0; ivtbl.data[k]; + FuncDeclaration* fd = dsym->isFuncDeclaration(); + assert(fd); + DtoForceDeclareDsymbol(fd); + assert(fd->llvmValue); + llvm::Constant* c = llvm::cast(fd->llvmValue); + // we have to bitcast, as the type created in ResolveClass expects a different this type + c = llvm::ConstantExpr::getBitCast(c, iri->vtblTy->getContainedType(k)); + iinits.push_back(c); + } + +#if 1 + for (size_t x=0; x< iinits.size(); ++x) + { + Logger::cout() << "field[" << x << "] = " << *ivtbl_ty->getElementType(x) << "\n\n"; + Logger::cout() << "init [" << x << "] = " << *iinits[x] << "\n\n"; + assert(ivtbl_ty->getElementType(x) == iinits[x]->getType()); + } +#endif + + llvm::Constant* civtblInit = llvm::ConstantStruct::get(ivtbl_ty, iinits); + iri->vtblInit = llvm::cast(civtblInit); + + idx++; + } + gIR->classes.pop_back(); gIR->structs.pop_back(); } @@ -330,8 +510,26 @@ bool def = false; if (cd->parent->isModule() && cd->getModule() == gIR->dmodule) { - ts->llvmInit->setInitializer(cd->llvmInitZ); - cd->llvmVtbl->setInitializer(cd->llvmConstVtbl); + // interfaces don't have initializers + if (!cd->isInterfaceDeclaration()) { + ts->llvmInit->setInitializer(cd->llvmInitZ); + cd->llvmVtbl->setInitializer(cd->llvmConstVtbl); + + // initialize interface vtables + IRStruct* irstruct = cd->llvmIRStruct; + std::vector infoInits; + for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) + { + IRInterface* iri = i->second; + iri->vtbl->setInitializer(iri->vtblInit); + infoInits.push_back(iri->infoInit); + } + // initialize interface info array + if (!infoInits.empty()) { + llvm::Constant* arrInit = llvm::ConstantArray::get(irstruct->interfaceInfosTy, infoInits); + irstruct->interfaceInfos->setInitializer(arrInit); + } + } def = true; } @@ -394,6 +592,54 @@ ////////////////////////////////////////////////////////////////////////////////////////// +DValue* DtoCastObjectToInterface(DValue* val, Type* _to) +{ + // call: + // Object _d_dynamic_cast(Object o, ClassInfo c) + + llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast"); + const llvm::FunctionType* funcTy = func->getFunctionType(); + + std::vector args; + + // Object o + llvm::Value* tmp = val->getRVal(); + tmp = DtoBitCast(tmp, funcTy->getParamType(0)); + args.push_back(tmp); + + // ClassInfo c + TypeClass* to = (TypeClass*)DtoDType(_to); + DtoForceDeclareDsymbol(to->sym); + assert(to->sym->llvmClass); + args.push_back(to->sym->llvmClass); + + // call it + llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "tmp"); + ret = DtoBitCast(ret, DtoType(_to)); + return new DImValue(_to, ret); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +DValue* DtoCastInterfaceToObject(DValue* val) +{ + // call: + // Object _d_toObject(void* p) + + llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_toObject"); + const llvm::FunctionType* funcTy = func->getFunctionType(); + + // void* p + llvm::Value* tmp = val->getRVal(); + tmp = DtoBitCast(tmp, funcTy->getParamType(0)); + + // call it + llvm::Value* ret = gIR->ir->CreateCall(func, tmp, "tmp"); + return new DImValue(ClassDeclaration::object->type, ret); +} + +////////////////////////////////////////////////////////////////////////////////////////// + void DtoDeclareClassInfo(ClassDeclaration* cd) { if (cd->llvmClassDeclared) return; @@ -407,7 +653,10 @@ std::string gname("_D"); gname.append(cd->mangle()); - gname.append("7__ClassZ"); + if (!cd->isInterfaceDeclaration()) + gname.append("7__ClassZ"); + else + gname.append("11__InterfaceZ"); const llvm::Type* st = cinfo->type->llvmType->get(); @@ -538,6 +787,7 @@ static uint build_classinfo_flags(ClassDeclaration* cd) { + // adapted from original dmd code uint flags = 0; //flags |= isCOMclass(); // IUnknown bool hasOffTi = false; @@ -591,12 +841,14 @@ assert(cd->type->ty == Tclass); assert(cd->llvmClass); - assert(cd->llvmInitZ); - assert(cd->llvmVtbl); - assert(cd->llvmConstVtbl); TypeClass* cdty = (TypeClass*)cd->type; - assert(cdty->llvmInit); + if (!cd->isInterfaceDeclaration()) { + assert(cd->llvmInitZ); + assert(cd->llvmVtbl); + assert(cd->llvmConstVtbl); + assert(cdty->llvmInit); + } // holds the list of initializers for llvm std::vector inits; @@ -617,10 +869,15 @@ // byte[] init const llvm::Type* byteptrty = llvm::PointerType::get(llvm::Type::Int8Ty); - c = llvm::ConstantExpr::getBitCast(cdty->llvmInit, byteptrty); - assert(!cd->llvmInitZ->getType()->isAbstract()); - size_t initsz = gTargetData->getTypeSize(cd->llvmInitZ->getType()); - c = DtoConstSlice(DtoConstSize_t(initsz), c); + if (cd->isInterfaceDeclaration()) { + c = cinfo->llvmInitZ->getOperand(1); + } + else { + c = llvm::ConstantExpr::getBitCast(cdty->llvmInit, byteptrty); + assert(!cd->llvmInitZ->getType()->isAbstract()); + size_t initsz = gTargetData->getTypeSize(cd->llvmInitZ->getType()); + c = DtoConstSlice(DtoConstSize_t(initsz), c); + } inits.push_back(c); // class name @@ -636,21 +893,34 @@ inits.push_back(c); // vtbl array - const llvm::Type* byteptrptrty = llvm::PointerType::get(byteptrty); - assert(!cd->llvmVtbl->getType()->isAbstract()); - c = llvm::ConstantExpr::getBitCast(cd->llvmVtbl, byteptrptrty); - assert(!cd->llvmConstVtbl->getType()->isAbstract()); - size_t vtblsz = gTargetData->getTypeSize(cd->llvmConstVtbl->getType()); - c = DtoConstSlice(DtoConstSize_t(vtblsz), c); + if (cd->isInterfaceDeclaration()) { + c = cinfo->llvmInitZ->getOperand(3); + } + else { + const llvm::Type* byteptrptrty = llvm::PointerType::get(byteptrty); + assert(!cd->llvmVtbl->getType()->isAbstract()); + c = llvm::ConstantExpr::getBitCast(cd->llvmVtbl, byteptrptrty); + assert(!cd->llvmConstVtbl->getType()->isAbstract()); + size_t vtblsz = cd->llvmConstVtbl->getType()->getNumElements(); + c = DtoConstSlice(DtoConstSize_t(vtblsz), c); + } inits.push_back(c); // interfaces array - // TODO - c = cinfo->llvmInitZ->getOperand(4); + IRStruct* irstruct = cd->llvmIRStruct; + if (cd->isInterfaceDeclaration() || !irstruct->interfaceInfos) { + c = cinfo->llvmInitZ->getOperand(4); + } + else { + const llvm::Type* t = cinfo->llvmInitZ->getOperand(4)->getType()->getContainedType(1); + c = llvm::ConstantExpr::getBitCast(irstruct->interfaceInfos, t); + size_t iisz = irstruct->interfaceInfosTy->getNumElements(); + c = DtoConstSlice(DtoConstSize_t(iisz), c); + } inits.push_back(c); // base classinfo - if (cd->baseClass) { + if (cd->baseClass && !cd->isInterfaceDeclaration()) { DtoDeclareClassInfo(cd->baseClass); c = cd->baseClass->llvmClass; assert(c); @@ -663,7 +933,12 @@ } // destructor - c = build_class_dtor(cd); + if (cd->isInterfaceDeclaration()) { + c = cinfo->llvmInitZ->getOperand(6); + } + else { + c = build_class_dtor(cd); + } inits.push_back(c); // invariant @@ -671,9 +946,14 @@ c = cinfo->llvmInitZ->getOperand(7); inits.push_back(c); - // uint flags, adapted from original dmd code - uint flags = build_classinfo_flags(cd); - c = DtoConstUint(flags); + // uint flags + if (cd->isInterfaceDeclaration()) { + c = cinfo->llvmInitZ->getOperand(8); + } + else { + uint flags = build_classinfo_flags(cd); + c = DtoConstUint(flags); + } inits.push_back(c); // allocator @@ -682,11 +962,16 @@ inits.push_back(c); // offset typeinfo - c = build_offti_array(cd, cinfo->llvmInitZ->getOperand(10)); + if (cd->isInterfaceDeclaration()) { + c = cinfo->llvmInitZ->getOperand(10); + } + else { + c = build_offti_array(cd, cinfo->llvmInitZ->getOperand(10)); + } inits.push_back(c); // default constructor - if (cd->defaultCtor) { + if (cd->defaultCtor && !cd->isInterfaceDeclaration()) { DtoForceDeclareDsymbol(cd->defaultCtor); c = isaConstant(cd->defaultCtor->llvmValue); //const llvm::Type* toTy = cinfo->llvmInitZ->getOperand(11)->getType(); diff -r 368547b1cbe6 -r 27b9f749d9fe gen/classes.h --- a/gen/classes.h Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/classes.h Sat Nov 24 06:33:00 2007 +0100 @@ -27,4 +27,7 @@ void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance); void DtoInitClass(TypeClass* tc, llvm::Value* dst); +DValue* DtoCastObjectToInterface(DValue* val, Type* to); +DValue* DtoCastInterfaceToObject(DValue* val); + #endif diff -r 368547b1cbe6 -r 27b9f749d9fe gen/functions.cpp --- a/gen/functions.cpp Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/functions.cpp Sat Nov 24 06:33:00 2007 +0100 @@ -192,7 +192,7 @@ if (AggregateDeclaration* ad = fdecl->isMember()) { Logger::print("isMember = this is: %s\n", ad->type->toChars()); thisty = DtoType(ad->type); - Logger::cout() << "this llvm type: " << *thisty << '\n'; + //Logger::cout() << "this llvm type: " << *thisty << '\n'; if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->recty.get())) thisty = llvm::PointerType::get(thisty); } @@ -277,7 +277,8 @@ DtoFunctionType(fdecl); // queue declaration - gIR->declareList.push_back(fdecl); + if (!fdecl->isAbstract()) + gIR->declareList.push_back(fdecl); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -290,6 +291,8 @@ Logger::println("DtoDeclareFunction(%s)", fdecl->toPrettyChars()); LOG_SCOPE; + assert(!fdecl->isAbstract()); + if (fdecl->llvmRunTimeHack) { Logger::println("runtime hack func chars: %s", fdecl->toChars()); if (!fdecl->llvmValue) diff -r 368547b1cbe6 -r 27b9f749d9fe gen/irstate.cpp --- a/gen/irstate.cpp Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/irstate.cpp Sat Nov 24 06:33:00 2007 +0100 @@ -107,6 +107,8 @@ type = t; defined = false; constinited = false; + interfaceInfosTy = NULL; + interfaceInfos = NULL; } ////////////////////////////////////////////////////////////////////////////////////////// diff -r 368547b1cbe6 -r 27b9f749d9fe gen/irstate.h --- a/gen/irstate.h Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/irstate.h Sat Nov 24 06:33:00 2007 +0100 @@ -8,6 +8,7 @@ #include #include "root.h" +#include "aggregate.h" // global ir state for current module struct IRState; @@ -20,6 +21,7 @@ struct FuncDeclaration; struct Module; struct TypeStruct; +struct BaseClass; /* struct LLVMValue @@ -39,6 +41,32 @@ IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e); }; +struct IRInterface : Object +{ + BaseClass* base; + ClassDeclaration* decl; + + const llvm::StructType* vtblTy; + llvm::ConstantStruct* vtblInit; + llvm::GlobalVariable* vtbl; + + const llvm::StructType* infoTy; + llvm::ConstantStruct* infoInit; + llvm::Constant* info; + + IRInterface(BaseClass* b, const llvm::StructType* vt) + { + base = b; + decl = b->base; + vtblTy = vt; + vtblInit = NULL; + vtbl = NULL; + infoTy = NULL; + infoInit = NULL; + info = NULL; + } +}; + // represents a struct or class struct IRStruct : Object { @@ -54,6 +82,8 @@ typedef std::multimap OffsetMap; typedef std::vector VarDeclVector; + typedef std::map InterfaceMap; + typedef InterfaceMap::iterator InterfaceIter; public: IRStruct(Type*); @@ -63,6 +93,10 @@ OffsetMap offsets; VarDeclVector defaultFields; + InterfaceMap interfaces; + const llvm::ArrayType* interfaceInfosTy; + llvm::GlobalVariable* interfaceInfos; + bool defined; bool constinited; }; diff -r 368547b1cbe6 -r 27b9f749d9fe gen/structs.cpp --- a/gen/structs.cpp Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/structs.cpp Sat Nov 24 06:33:00 2007 +0100 @@ -445,7 +445,7 @@ } } - { + /*{ LOG_SCOPE; Logger::println("******** DUnion BEGIN"); size_t n = fields.size(); @@ -458,7 +458,7 @@ } } Logger::println("******** DUnion END"); - } + }*/ } static void push_nulls(size_t nbytes, std::vector& out) diff -r 368547b1cbe6 -r 27b9f749d9fe gen/toir.cpp --- a/gen/toir.cpp Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/toir.cpp Sat Nov 24 06:33:00 2007 +0100 @@ -1230,10 +1230,10 @@ if (p->topexp() && p->topexp()->e1 == this) { Logger::println("lval PtrExp"); - //if (a->isField()) return a; return new DVarValue(type, a->getRVal(), true); } + // this should be deterministic but right now lvalue casts don't propagate lvalueness !?! llvm::Value* lv = a->getRVal(); llvm::Value* v = lv; if (DtoCanLoad(v)) @@ -1253,7 +1253,7 @@ Type* t = DtoDType(type); Type* e1type = DtoDType(e1->type); - Logger::print("e1->type=%s\n", e1type->toChars()); + Logger::print("e1type=%s\n", e1type->toChars()); if (VarDeclaration* vd = var->isVarDeclaration()) { llvm::Value* arrptr; @@ -1265,7 +1265,7 @@ std::vector vdoffsets; arrptr = DtoIndexStruct(src, ts->sym, vd->type, vd->offset, vdoffsets); } - else if (e1->type->ty == Tclass) { + else if (e1type->ty == Tclass) { TypeClass* tc = (TypeClass*)e1type; Logger::println("Class member offset: %d", vd->offset); std::vector vdoffsets(1,0); @@ -1282,14 +1282,19 @@ } else if (FuncDeclaration* fdecl = var->isFuncDeclaration()) { - if (fdecl->llvmValue == 0) - { - DtoForceDeclareDsymbol(fdecl); + DtoResolveDsymbol(fdecl); + + llvm::Value* funcval; + llvm::Value* vthis2 = 0; + if (e1type->ty == Tclass) { + TypeClass* tc = (TypeClass*)e1type; + if (tc->sym->isInterfaceDeclaration()) { + vthis2 = DtoCastInterfaceToObject(l)->getRVal(); + } } - - llvm::Value* funcval = fdecl->llvmValue; llvm::Value* vthis = l->getRVal(); - unsigned cc = (unsigned)-1; + if (!vthis2) vthis2 = vthis; + //unsigned cc = (unsigned)-1; // virtual call if (!fdecl->isFinal() && fdecl->isVirtual()) { @@ -1303,10 +1308,17 @@ funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); funcval = DtoGEP(funcval, zero, vtblidx, toChars(), p->scopebb()); funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); - assert(funcval->getType() == fdecl->llvmValue->getType()); - cc = DtoCallingConv(fdecl->linkage); + //assert(funcval->getType() == DtoType(fdecl->type)); + //cc = DtoCallingConv(fdecl->linkage); } - return new DFuncValue(fdecl, funcval, vthis); + // static call + else { + DtoForceDeclareDsymbol(fdecl); + funcval = fdecl->llvmValue; + assert(funcval); + //assert(funcval->getType() == DtoType(fdecl->type)); + } + return new DFuncValue(fdecl, funcval, vthis2); } else { printf("unknown: %s\n", var->toChars()); @@ -1829,15 +1841,14 @@ //assert(e1->type->ty != Tclass); DValue* v = e1->toElem(p); - llvm::Value* val = v->getRVal(); + const llvm::Type* t = DtoType(v->getType()); llvm::Value* ldval = 0; - - const llvm::Type* t = val->getType(); llvm::Constant* z = llvm::Constant::getNullValue(t); Type* e1type = DtoDType(e1->type); if (e1type->ty == Tpointer) { + llvm::Value* val = v->getRVal(); Logger::cout() << *z << '\n'; Logger::cout() << *val << '\n'; new llvm::FreeInst(val, p->scopebb()); @@ -1845,16 +1856,23 @@ } else if (e1type->ty == Tclass) { TypeClass* tc = (TypeClass*)e1type; - DtoCallClassDtors(tc, val); + llvm::Value* val = 0; + if (tc->sym->dtors.dim > 0) { + val = v->getRVal(); + DtoCallClassDtors(tc, val); + } if (DVarValue* vv = v->isVar()) { - if (vv->var && !vv->var->onstack) + if (vv->var && !vv->var->onstack) { + if (!val) val = v->getRVal(); new llvm::FreeInst(val, p->scopebb()); + } } new llvm::StoreInst(z, v->getLVal(), p->scopebb()); } else if (e1type->ty == Tarray) { // must be on the heap (correct?) + llvm::Value* val = v->getRVal(); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); llvm::Value* ptr = DtoGEP(val,zero,one,"tmp",p->scopebb()); diff -r 368547b1cbe6 -r 27b9f749d9fe gen/tollvm.cpp --- a/gen/tollvm.cpp Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/tollvm.cpp Sat Nov 24 06:33:00 2007 +0100 @@ -1140,11 +1140,35 @@ DValue* DtoCastClass(DValue* val, Type* _to) { - const llvm::Type* tolltype = DtoType(_to); Type* to = DtoDType(_to); - assert(to->ty == Tclass || to->ty == Tpointer); - llvm::Value* rval = new llvm::BitCastInst(val->getRVal(), tolltype, "tmp", gIR->scopebb()); - return new DImValue(_to, rval); + if (to->ty == Tpointer) { + const llvm::Type* tolltype = DtoType(_to); + llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype); + return new DImValue(_to, rval); + } + + assert(to->ty == Tclass); + TypeClass* tc = (TypeClass*)to; + + Type* from = DtoDType(val->getType()); + TypeClass* fc = (TypeClass*)from; + + if (tc->sym->isInterfaceDeclaration()) { + assert(!fc->sym->isInterfaceDeclaration()); + return DtoCastObjectToInterface(val, _to); + } + else { + if (fc->sym->isInterfaceDeclaration()) { + assert(0); + return DtoCastInterfaceToObject(val); + } + else { + const llvm::Type* tolltype = DtoType(_to); + assert(to->ty == Tclass); + llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype); + return new DImValue(_to, rval); + } + } } DValue* DtoCast(DValue* val, Type* to) diff -r 368547b1cbe6 -r 27b9f749d9fe gen/toobj.cpp --- a/gen/toobj.cpp Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/toobj.cpp Sat Nov 24 06:33:00 2007 +0100 @@ -389,7 +389,9 @@ unsigned idx = 0; unsigned r = LLVM_ClassOffsetToIndex(this, os, idx); assert(r != (unsigned)-1 && "Offset not found in any aggregate field"); - result.push_back(r+1); // vtable is 0 + r++; // vtable is 0 + r += vtblInterfaces->dim; + result.push_back(r); } /* ================================================================== */ diff -r 368547b1cbe6 -r 27b9f749d9fe gen/typinf.cpp --- a/gen/typinf.cpp Thu Nov 22 22:30:10 2007 +0100 +++ b/gen/typinf.cpp Sat Nov 24 06:33:00 2007 +0100 @@ -1029,76 +1029,127 @@ void TypeInfoInterfaceDeclaration::llvmDeclare() { - assert(0 && "TypeInfoTupleDeclaration"); + Logger::println("TypeInfoInterfaceDeclaration::llvmDeclare() %s", toChars()); + LOG_SCOPE; + + // init typeinfo class + ClassDeclaration* base = Type::typeinfointerface; + assert(base); + DtoResolveClass(base); + + // get type of typeinfo class + const llvm::StructType* stype = isaStruct(base->type->llvmType->get()); + + // create the symbol + llvmValue = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); } void TypeInfoInterfaceDeclaration::llvmDefine() { - assert(0 && "TypeInfoTupleDeclaration"); + Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // init typeinfo class + ClassDeclaration* base = Type::typeinfointerface; + assert(base); + DtoForceConstInitDsymbol(base); + + // get type of typeinfo class + const llvm::StructType* stype = isaStruct(base->type->llvmType->get()); + + // initializer vector + std::vector sinits; + // first is always the vtable + sinits.push_back(base->llvmVtbl); + + // get classinfo + assert(tinfo->ty == Tclass); + TypeClass *tc = (TypeClass *)tinfo; + assert(tc->sym->llvmClass); + sinits.push_back(tc->sym->llvmClass); + + // create the symbol + llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits); + isaGlobalVar(llvmValue)->setInitializer(tiInit); } void TypeInfoInterfaceDeclaration::toDt(dt_t **pdt) { - assert(0 && "TypeInfoInterfaceDeclaration"); - - /* - //printf("TypeInfoInterfaceDeclaration::toDt() %s\n", tinfo->toChars()); - dtxoff(pdt, Type::typeinfointerface->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfoInterface - dtdword(pdt, 0); // monitor - - assert(tinfo->ty == Tclass); - - TypeClass *tc = (TypeClass *)tinfo; - Symbol *s; - - if (!tc->sym->vclassinfo) - tc->sym->vclassinfo = new ClassInfoDeclaration(tc->sym); - s = tc->sym->vclassinfo->toSymbol(); - dtxoff(pdt, s, 0, TYnptr); // ClassInfo for tinfo - */ + assert(0); } /* ========================================================================= */ void TypeInfoTupleDeclaration::llvmDeclare() { - assert(0 && "TypeInfoTupleDeclaration"); + Logger::println("TypeInfoTupleDeclaration::llvmDeclare() %s", toChars()); + LOG_SCOPE; + + // init typeinfo class + ClassDeclaration* base = Type::typeinfotypelist; + assert(base); + DtoResolveClass(base); + + // get type of typeinfo class + const llvm::StructType* stype = isaStruct(base->type->llvmType->get()); + + // create the symbol + llvmValue = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); } void TypeInfoTupleDeclaration::llvmDefine() { - assert(0 && "TypeInfoTupleDeclaration"); + Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // init typeinfo class + ClassDeclaration* base = Type::typeinfotypelist; + assert(base); + DtoForceConstInitDsymbol(base); + + // get type of typeinfo class + const llvm::StructType* stype = isaStruct(base->type->llvmType->get()); + + // initializer vector + std::vector sinits; + // first is always the vtable + sinits.push_back(base->llvmVtbl); + + // create elements array + assert(tinfo->ty == Ttuple); + TypeTuple *tu = (TypeTuple *)tinfo; + + size_t dim = tu->arguments->dim; + std::vector arrInits; + + const llvm::Type* tiTy = Type::typeinfo->type->llvmType->get(); + tiTy = llvm::PointerType::get(tiTy); + + for (size_t i = 0; i < dim; i++) + { + Argument *arg = (Argument *)tu->arguments->data[i]; + arg->type->getTypeInfo(NULL); + DtoForceDeclareDsymbol(arg->type->vtinfo); + assert(arg->type->vtinfo->llvmValue); + llvm::Constant* c = isaConstant(arg->type->vtinfo->llvmValue); + c = llvm::ConstantExpr::getBitCast(c, tiTy); + arrInits.push_back(c); + } + + // build array type + const llvm::ArrayType* arrTy = llvm::ArrayType::get(tiTy, dim); + llvm::Constant* arrC = llvm::ConstantArray::get(arrTy, arrInits); + + // build the slice + llvm::Constant* slice = DtoConstSlice(DtoConstSize_t(dim), arrC); + sinits.push_back(slice); + + // create the symbol + llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits); + isaGlobalVar(llvmValue)->setInitializer(tiInit); } void TypeInfoTupleDeclaration::toDt(dt_t **pdt) { - assert(0 && "TypeInfoTupleDeclaration"); - - /* - //printf("TypeInfoTupleDeclaration::toDt() %s\n", tinfo->toChars()); - dtxoff(pdt, Type::typeinfotypelist->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfoInterface - dtdword(pdt, 0); // monitor - - assert(tinfo->ty == Ttuple); - - TypeTuple *tu = (TypeTuple *)tinfo; - - size_t dim = tu->arguments->dim; - dtdword(pdt, dim); // elements.length - - dt_t *d = NULL; - for (size_t i = 0; i < dim; i++) - { Argument *arg = (Argument *)tu->arguments->data[i]; - Expression *e = arg->type->getTypeInfo(NULL); - e = e->optimize(WANTvalue); - e->toDt(&d); - } - - Symbol *s; - s = static_sym(); - s->Sdt = d; - outdata(s); - - dtxoff(pdt, s, 0, TYnptr); // elements.ptr - */ + assert(0); } diff -r 368547b1cbe6 -r 27b9f749d9fe llvmdc.kdevelop.filelist --- a/llvmdc.kdevelop.filelist Thu Nov 22 22:30:10 2007 +0100 +++ b/llvmdc.kdevelop.filelist Sat Nov 24 06:33:00 2007 +0100 @@ -148,6 +148,7 @@ lphobos/internal/aaA.d lphobos/internal/adi.d lphobos/internal/arrays.d +lphobos/internal/cast.d lphobos/internal/contract.d lphobos/internal/mem.d lphobos/internal/moduleinit.d @@ -338,7 +339,6 @@ test/classinfo2.d test/classinfo3.d test/classinfo4.d -test/classinfo5.d test/comma.d test/complex1.d test/complex2.d @@ -378,6 +378,10 @@ test/imports2.d test/imports_1of2.d test/imports_2of2.d +test/interface1.d +test/interface2.d +test/interface3.d +test/interface4.d test/intrinsics.d test/mainargs1.d test/memory1.d diff -r 368547b1cbe6 -r 27b9f749d9fe lphobos/build.sh --- a/lphobos/build.sh Thu Nov 22 22:30:10 2007 +0100 +++ b/lphobos/build.sh Sat Nov 24 06:33:00 2007 +0100 @@ -27,6 +27,10 @@ rebuild typeinfos2.d -c -oqobj -dc=llvmdc-posix || exit 1 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/typeinfo2.*.bc` ../lib/llvmdcore.bc || exit 1 +echo "compiling object/interface casting runtime support" +llvmdc internal/cast.d -c -odobj || exit 1 +llvm-link -f -o=../lib/llvmdcore.bc obj/cast.bc ../lib/llvmdcore.bc || exit 1 + echo "compiling string foreach runtime support" llvmdc internal/aApply.d -c -odobj || exit 1 llvmdc internal/aApplyR.d -c -odobj || exit 1 diff -r 368547b1cbe6 -r 27b9f749d9fe lphobos/internal/cast.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lphobos/internal/cast.d Sat Nov 24 06:33:00 2007 +0100 @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + + +import object; +import std.c.stdio; + +extern (C): + +/****************************************** + * Given a pointer: + * If it is an Object, return that Object. + * If it is an interface, return the Object implementing the interface. + * If it is null, return null. + * Else, undefined crash + */ + +Object _d_toObject(void* p) +{ Object o; + + if (p) + { + o = cast(Object)p; + //ClassInfo oc = o.classinfo; + Interface *pi = **cast(Interface ***)p; + + /* Interface.offset lines up with ClassInfo.name.ptr, + * so we rely on pointers never being less than 64K, + * and Objects never being greater. + */ + if (pi.offset < 0x10000) + { + //printf("\tpi.offset = %d\n", pi.offset); + o = cast(Object)(p - pi.offset); + } + } + return o; +} + + +/************************************* + * Attempts to cast Object o to class c. + * Returns o if successful, null if not. + */ + +Object _d_interface_cast(void* p, ClassInfo c) +{ Object o; + + //printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name); + if (p) + { + Interface *pi = **cast(Interface ***)p; + + //printf("\tpi.offset = %d\n", pi.offset); + o = cast(Object)(p - pi.offset); + return _d_dynamic_cast(o, c); + } + return o; +} + +Object _d_dynamic_cast(Object o, ClassInfo c) +{ ClassInfo oc; + uint offset = 0; + + //printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name); + + if (o) + { + oc = o.classinfo; + if (_d_isbaseof2(oc, c, offset)) + { + //printf("\toffset = %d\n", offset); + o = cast(Object)(cast(void*)o + offset); + } + else + o = null; + } + //printf("\tresult = %p\n", o); + return o; +} + +int _d_isbaseof2(ClassInfo oc, ClassInfo c, inout uint offset) +{ int i; + + if (oc is c) + return 1; + do + { + if (oc.base is c) + return 1; + for (i = 0; i < oc.interfaces.length; i++) + { + ClassInfo ic; + + ic = oc.interfaces[i].classinfo; + if (ic is c) + { offset = oc.interfaces[i].offset; + return 1; + } + } + for (i = 0; i < oc.interfaces.length; i++) + { + ClassInfo ic; + + ic = oc.interfaces[i].classinfo; + if (_d_isbaseof2(ic, c, offset)) + { offset = oc.interfaces[i].offset; + return 1; + } + } + oc = oc.base; + } while (oc); + return 0; +} + +int _d_isbaseof(ClassInfo oc, ClassInfo c) +{ int i; + + if (oc is c) + return 1; + do + { + if (oc.base is c) + return 1; + for (i = 0; i < oc.interfaces.length; i++) + { + ClassInfo ic; + + ic = oc.interfaces[i].classinfo; + if (ic is c || _d_isbaseof(ic, c)) + return 1; + } + oc = oc.base; + } while (oc); + return 0; +} + +/********************************* + * Find the vtbl[] associated with Interface ic. + */ + +void *_d_interface_vtbl(ClassInfo ic, Object o) +{ int i; + ClassInfo oc; + + //printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic); + + assert(o); + + oc = o.classinfo; + for (i = 0; i < oc.interfaces.length; i++) + { + ClassInfo oic; + + oic = oc.interfaces[i].classinfo; + if (oic is ic) + { + return cast(void *)oc.interfaces[i].vtbl; + } + } + assert(0); +} diff -r 368547b1cbe6 -r 27b9f749d9fe lphobos/internal/objectimpl.d --- a/lphobos/internal/objectimpl.d Thu Nov 22 22:30:10 2007 +0100 +++ b/lphobos/internal/objectimpl.d Sat Nov 24 06:33:00 2007 +0100 @@ -879,8 +879,6 @@ ClassInfo info; } -/+ - class TypeInfo_Interface : TypeInfo { char[] toString() { return info.name; } @@ -944,8 +942,6 @@ ClassInfo info; } -+/ - class TypeInfo_Struct : TypeInfo { char[] toString() { return name; } @@ -1038,8 +1034,6 @@ uint m_flags; } -/+ - class TypeInfo_Tuple : TypeInfo { TypeInfo[] elements; @@ -1102,8 +1096,6 @@ } } -+/ - class TypeInfo_Const : TypeInfo { char[] toString() { return "const " ~ base.toString(); } diff -r 368547b1cbe6 -r 27b9f749d9fe test/interface1.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/interface1.d Sat Nov 24 06:33:00 2007 +0100 @@ -0,0 +1,22 @@ +module interface1; + +interface Inter +{ + void func(); +} + +class Class : Inter +{ + override void func() + { + printf("hello world\n"); + } +} + +void main() +{ + scope c = new Class; + c.func(); + Inter i = c; + i.func(); +} diff -r 368547b1cbe6 -r 27b9f749d9fe test/interface2.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/interface2.d Sat Nov 24 06:33:00 2007 +0100 @@ -0,0 +1,35 @@ +module interface2; + +interface A +{ + void a(); +} + +interface B +{ + void b(); +} + +class C : A,B +{ + int i = 0; + override void a() + { + printf("hello from C.a\n"); + } + override void b() + { + printf("hello from C.b\n"); + } +} + +void main() +{ + scope c = new C; + {c.a(); + c.b();} + {A a = c; + a.a();} + {B b = c; + b.b();} +} diff -r 368547b1cbe6 -r 27b9f749d9fe test/interface3.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/interface3.d Sat Nov 24 06:33:00 2007 +0100 @@ -0,0 +1,28 @@ +module interface3; + +interface I +{ + void func(); +} + +class C : I +{ + int i = 42; + override void func() + { + printf("hello %d\n", i); + i++; + } +} + +void main() +{ + scope c = new C; + {c.func();} + { + I i = c; + {i.func();} + } + {printf("final %d\n", c.i);} + {assert(c.i == 44);} +} diff -r 368547b1cbe6 -r 27b9f749d9fe test/interface4.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/interface4.d Sat Nov 24 06:33:00 2007 +0100 @@ -0,0 +1,33 @@ +module interface4; + +interface I +{ + void func(); +} + +interface I2 +{ + void func(); +} + +class C : I,I2 +{ + int i = 42; + override void func() + { + printf("hello %d\n", i); + i++; + } +} + +void main() +{ + scope c = new C; + c.func(); + I i = c; + i.func(); + I2 i2 = c; + i2.func(); + printf("final %d\n", c.i); + assert(c.i == 45); +}