void visit(TypeInfoStructDeclaration *decl) override { IF_LOG Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; // make sure struct is resolved assert(decl->tinfo->ty == Tstruct); TypeStruct *tc = static_cast<TypeStruct *>(decl->tinfo); StructDeclaration *sd = tc->sym; // check declaration in object.d const auto structTypeInfoType = getStructTypeInfoType(); const auto structTypeInfoDecl = Type::typeinfostruct; // On x86_64, class TypeInfo_Struct contains 2 additional fields // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs // implementation. They are not present on any other cpu/os. const bool isX86_64 = global.params.targetTriple->getArch() == llvm::Triple::x86_64; const unsigned expectedFields = 11 + (isX86_64 ? 2 : 0); const unsigned actualFields = structTypeInfoDecl->fields.dim - 1; // union of xdtor/xdtorti counts as 2 overlapping fields if (actualFields != expectedFields) { error(Loc(), "Unexpected number of `object.TypeInfo_Struct` fields; " "druntime version does not match compiler"); fatal(); } RTTIBuilder b(structTypeInfoType); // handle opaque structs if (!sd->members) { Logger::println("is opaque struct, emitting dummy TypeInfo_Struct"); b.push_null_void_array(); // name b.push_null_void_array(); // m_init b.push_null_vp(); // xtoHash b.push_null_vp(); // xopEquals b.push_null_vp(); // xopCmp b.push_null_vp(); // xtoString b.push_uint(0); // m_flags b.push_null_vp(); // xdtor/xdtorti b.push_null_vp(); // xpostblit b.push_uint(0); // m_align if (isX86_64) { b.push_null_vp(); // m_arg1 b.push_null_vp(); // m_arg2 } b.push_null_vp(); // m_RTInfo b.finalize(gvar); return; } // can't emit typeinfo for forward declarations if (sd->sizeok != SIZEOKdone) { sd->error("cannot emit `TypeInfo` for forward declaration"); fatal(); } DtoResolveStruct(sd); if (TemplateInstance *ti = sd->isInstantiated()) { if (!ti->needsCodegen()) { assert(ti->minst || sd->requestTypeInfo); // We won't emit ti, so emit the special member functions in here. if (sd->xeq && sd->xeq != StructDeclaration::xerreq && sd->xeq->semanticRun >= PASSsemantic3) { Declaration_codegen(sd->xeq); } if (sd->xcmp && sd->xcmp != StructDeclaration::xerrcmp && sd->xcmp->semanticRun >= PASSsemantic3) { Declaration_codegen(sd->xcmp); } if (FuncDeclaration *ftostr = search_toString(sd)) { if (ftostr->semanticRun >= PASSsemantic3) Declaration_codegen(ftostr); } if (sd->xhash && sd->xhash->semanticRun >= PASSsemantic3) { Declaration_codegen(sd->xhash); } if (sd->postblit && sd->postblit->semanticRun >= PASSsemantic3) { Declaration_codegen(sd->postblit); } if (sd->dtor && sd->dtor->semanticRun >= PASSsemantic3) { Declaration_codegen(sd->dtor); } if (sd->tidtor && sd->tidtor->semanticRun >= PASSsemantic3) { Declaration_codegen(sd->tidtor); } } } IrAggr *iraggr = getIrAggr(sd); // string name b.push_string(sd->toPrettyChars()); // void[] m_init // The protocol is to write a null pointer for zero-initialized arrays. The // length field is always needed for tsize(). llvm::Constant *initPtr; if (tc->isZeroInit(Loc())) { initPtr = getNullValue(getVoidPtrType()); } else { initPtr = iraggr->getInitSymbol(); } b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr); // function xtoHash FuncDeclaration *fd = sd->xhash; b.push_funcptr(fd); // function xopEquals fd = sd->xeq; b.push_funcptr(fd); // function xopCmp fd = sd->xcmp; b.push_funcptr(fd); // function xtoString fd = search_toString(sd); b.push_funcptr(fd); // uint m_flags unsigned hasptrs = tc->hasPointers() ? 1 : 0; b.push_uint(hasptrs); // function xdtor/xdtorti b.push_funcptr(sd->tidtor); // function xpostblit FuncDeclaration *xpostblit = sd->postblit; if (xpostblit && sd->postblit->storage_class & STCdisable) { xpostblit = nullptr; } b.push_funcptr(xpostblit); // uint m_align b.push_uint(DtoAlignment(tc)); if (isX86_64) { // TypeInfo m_arg1 // TypeInfo m_arg2 Type *t = sd->arg1type; for (unsigned i = 0; i < 2; i++) { if (t) { t = merge(t); b.push_typeinfo(t); } else { b.push_null(getTypeInfoType()); } t = sd->arg2type; } } // immutable(void)* m_RTInfo // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. if (sd->getRTInfo) { b.push(toConstElem(sd->getRTInfo, gIR)); } else if (!tc->hasPointers()) { b.push_size_as_vp(0); // no pointers } else { b.push_size_as_vp(1); // has pointers } // finish b.finalize(gvar); }
void visit(TypeInfoStructDeclaration *decl) { IF_LOG Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; // make sure struct is resolved assert(decl->tinfo->ty == Tstruct); TypeStruct *tc = static_cast<TypeStruct *>(decl->tinfo); StructDeclaration *sd = tc->sym; // handle opaque structs if (!sd->members) { RTTIBuilder b(Type::typeinfostruct); b.finalize(getIrGlobal(decl)); return; } // can't emit typeinfo for forward declarations if (sd->sizeok != SIZEOKdone) { sd->error("cannot emit TypeInfo for forward declaration"); fatal(); } DtoResolveStruct(sd); IrAggr* iraggr = getIrAggr(sd); RTTIBuilder b(Type::typeinfostruct); // char[] name b.push_string(sd->toPrettyChars()); // void[] init // The protocol is to write a null pointer for zero-initialized arrays. The // length field is always needed for tsize(). llvm::Constant *initPtr; if (tc->isZeroInit(Loc())) initPtr = getNullValue(getVoidPtrType()); else initPtr = iraggr->getInitSymbol(); b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr); // well use this module for all overload lookups // toHash FuncDeclaration* fd = sd->xhash; b.push_funcptr(fd); // opEquals fd = sd->xeq; b.push_funcptr(fd); // opCmp fd = sd->xcmp; b.push_funcptr(fd); // toString fd = search_toString(sd); b.push_funcptr(fd); // uint m_flags; unsigned hasptrs = tc->hasPointers() ? 1 : 0; b.push_uint(hasptrs); // On x86_64, class TypeInfo_Struct contains 2 additional fields // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs // implementation. They are not present on any other cpu/os. assert((global.params.targetTriple.getArch() != llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 11) || (global.params.targetTriple.getArch() == llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 13)); //void function(void*) xdtor; b.push_funcptr(sd->dtor); //void function(void*) xpostblit; FuncDeclaration *xpostblit = sd->postblit; if (xpostblit && sd->postblit->storage_class & STCdisable) xpostblit = 0; b.push_funcptr(xpostblit); //uint m_align; b.push_uint(tc->alignsize()); if (global.params.is64bit) { // TypeInfo m_arg1; // TypeInfo m_arg2; Type *t = sd->arg1type; for (unsigned i = 0; i < 2; i++) { if (t) { t = t->merge(); b.push_typeinfo(t); } else b.push_null(Type::dtypeinfo->type); t = sd->arg2type; } } // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. if (sd->getRTInfo) b.push(toConstElem(sd->getRTInfo, gIR)); else if (!tc->hasPointers()) b.push_size_as_vp(0); // no pointers else b.push_size_as_vp(1); // has pointers // finish b.finalize(getIrGlobal(decl)); }