void visit(ClassDeclaration *decl) override { IF_LOG Logger::println("ClassDeclaration::codegen: '%s'", decl->toPrettyChars()); LOG_SCOPE assert(!irs->dcomputetarget); if (decl->ir->isDefined()) { return; } if (decl->type->ty == Terror) { error(decl->loc, "had semantic errors when compiling"); decl->ir->setDefined(); return; } if (decl->members && decl->symtab) { DtoResolveClass(decl); decl->ir->setDefined(); for (auto m : *decl->members) { m->accept(this); } IrAggr *ir = getIrAggr(decl); const auto lwc = DtoLinkage(decl); auto &initZ = ir->getInitSymbol(); auto initGlobal = llvm::cast<LLGlobalVariable>(initZ); initZ = irs->setGlobalVarInitializer(initGlobal, ir->getDefaultInit()); setLinkage(lwc, initGlobal); llvm::GlobalVariable *vtbl = ir->getVtblSymbol(); vtbl->setInitializer(ir->getVtblInit()); setLinkage(lwc, vtbl); llvm::GlobalVariable *classZ = ir->getClassInfoSymbol(); if (!isSpeculativeType(decl->type)) { classZ->setInitializer(ir->getClassInfoInit()); setLinkage(lwc, classZ); } } }
LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) { // The layout is: // { // void **vptr; // monitor_t monitor; // byte[] initializer; // static initialization data // char[] name; // class name // void *[] vtbl; // Interface[] interfaces; // ClassInfo *base; // base class // void *destructor; // void *invariant; // class invariant // uint flags; // void *deallocator; // OffsetTypeInfo[] offTi; // void *defaultConstructor; // version(D_Version2) // immutable(void)* m_RTInfo; // else // TypeInfo typeinfo; // since dmd 1.045 // } Logger::println("DtoDefineClassInfo(%s)", cd->toChars()); LOG_SCOPE; assert(cd->type->ty == Tclass); TypeClass* cdty = static_cast<TypeClass*>(cd->type); IrAggr* ir = cd->ir.irAggr; assert(ir); ClassDeclaration* cinfo = ClassDeclaration::classinfo; if (cinfo->fields.dim != 12) { error("object.d ClassInfo class is incorrect"); fatal(); } // use the rtti builder RTTIBuilder b(ClassDeclaration::classinfo); LLConstant* c; LLType* voidPtr = getVoidPtrType(); LLType* voidPtrPtr = getPtrToType(voidPtr); // byte[] init if (cd->isInterfaceDeclaration()) { b.push_null_void_array(); } else { LLType* cd_type = cdty->irtype->isClass()->getMemoryLLType(); size_t initsz = getTypePaddedSize(cd_type); b.push_void_array(initsz, ir->getInitSymbol()); } // class name // code from dmd const char *name = cd->ident->toChars(); size_t namelen = strlen(name); if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) { name = cd->toPrettyChars(); namelen = strlen(name); } b.push_string(name); // vtbl array if (cd->isInterfaceDeclaration()) { b.push_array(0, getNullValue(voidPtrPtr)); } else { c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr); b.push_array(cd->vtbl.dim, c); } // interfaces array b.push(ir->getClassInfoInterfaces()); // base classinfo // interfaces never get a base , just the interfaces[] if (cd->baseClass && !cd->isInterfaceDeclaration()) b.push_classinfo(cd->baseClass); else b.push_null(cinfo->type); // destructor if (cd->isInterfaceDeclaration()) b.push_null_vp(); else b.push(build_class_dtor(cd)); // invariant VarDeclaration* invVar = static_cast<VarDeclaration*>(cinfo->fields.data[6]); b.push_funcptr(cd->inv, invVar->type); // uint flags unsigned flags; if (cd->isInterfaceDeclaration()) flags = 4 | cd->isCOMinterface() | 32; else flags = build_classinfo_flags(cd); b.push_uint(flags); // deallocator b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo()); // offset typeinfo VarDeclaration* offTiVar = static_cast<VarDeclaration*>(cinfo->fields.data[9]); #if GENERATE_OFFTI if (cd->isInterfaceDeclaration()) b.push_null(offTiVar->type); else b.push(build_offti_array(cd, DtoType(offTiVar->type))); #else // GENERATE_OFFTI b.push_null(offTiVar->type); #endif // GENERATE_OFFTI // default constructor VarDeclaration* defConstructorVar = static_cast<VarDeclaration*>(cinfo->fields.data[10]); b.push_funcptr(cd->defaultCtor, defConstructorVar->type); // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. if (cd->getRTInfo) b.push(cd->getRTInfo->toConstElem(gIR)); else if (flags & 2) b.push_size_as_vp(0); // no pointers else b.push_size_as_vp(1); // has pointers /*size_t n = inits.size(); for (size_t i=0; i<n; ++i) { Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n'; }*/ // build the initializer LLType *initType = ir->classInfo->getType()->getContainedType(0); LLConstant* finalinit = b.get_constant(isaStruct(initType)); //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; ir->constClassInfo = finalinit; // sanity check assert(finalinit->getType() == initType && "__ClassZ initializer does not match the ClassInfo type"); // return initializer return finalinit; }
void DtoResolveClass(ClassDeclaration* cd) { // make sure the base classes are processed first ArrayIter<BaseClass> base_iter(cd->baseclasses); while (base_iter.more()) { BaseClass* bc = base_iter.get(); if (bc) { bc->base->codegen(Type::sir); } base_iter.next(); } if (cd->ir.resolved) return; cd->ir.resolved = true; Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; // make sure type exists DtoType(cd->type); // create IrAggr assert(cd->ir.irAggr == NULL); IrAggr* irAggr = new IrAggr(cd); cd->ir.irAggr = irAggr; // make sure all fields really get their ir field ArrayIter<VarDeclaration> it(cd->fields); for (; !it.done(); it.next()) { VarDeclaration* vd = it.get(); if (vd->ir.irField == NULL) { new IrField(vd); } else { IF_LOG Logger::println("class field already exists!!!"); } } bool needs_def = mustDefineSymbol(cd); // emit the ClassZ symbol LLGlobalVariable* ClassZ = irAggr->getClassInfoSymbol(); // emit the interfaceInfosZ symbol if necessary if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) irAggr->getInterfaceArraySymbol(); // initializer is applied when it's built // interface only emit typeinfo and classinfo if (cd->isInterfaceDeclaration()) { irAggr->initializeInterface(); } else { // emit the initZ symbol LLGlobalVariable* initZ = irAggr->getInitSymbol(); // emit the vtblZ symbol LLGlobalVariable* vtblZ = irAggr->getVtblSymbol(); // perform definition if (needs_def) { // set symbol initializers initZ->setInitializer(irAggr->getDefaultInit()); vtblZ->setInitializer(irAggr->getVtblInit()); } } // emit members if (cd->members) { ArrayIter<Dsymbol> it(*cd->members); while (!it.done()) { Dsymbol* member = it.get(); if (member) member->codegen(Type::sir); it.next(); } } if (needs_def) { // emit typeinfo DtoTypeInfoOf(cd->type); // define classinfo ClassZ->setInitializer(irAggr->getClassInfoInit()); } }