// Put out instance of ModuleInfo for this Module void Module::genmoduleinfo() { // resolve ModuleInfo if (!moduleinfo) { error("object.d is missing the ModuleInfo struct"); fatal(); } // check for patch else { unsigned sizeof_ModuleInfo = 16 * Target::ptrsize; if (sizeof_ModuleInfo != moduleinfo->structsize) { error("object.d ModuleInfo class is incorrect"); fatal(); } } // use the RTTIBuilder RTTIBuilder b(moduleinfo); // some types LLType* moduleinfoTy = moduleinfo->type->irtype->getLLType(); LLType* classinfoTy = ClassDeclaration::classinfo->type->irtype->getLLType(); // importedModules[] std::vector<LLConstant*> importInits; LLConstant* importedModules = 0; llvm::ArrayType* importedModulesTy = 0; for (size_t i = 0; i < aimports.dim; i++) { Module *m = static_cast<Module *>(aimports.data[i]); if (!m->needModuleInfo() || m == this) continue; // declare the imported module info std::string m_name("_D"); m_name.append(m->mangle()); m_name.append("12__ModuleInfoZ"); llvm::GlobalVariable* m_gvar = gIR->module->getGlobalVariable(m_name); if (!m_gvar) m_gvar = new llvm::GlobalVariable(*gIR->module, moduleinfoTy, false, llvm::GlobalValue::ExternalLinkage, NULL, m_name); importInits.push_back(m_gvar); } // has import array? if (!importInits.empty()) { importedModulesTy = llvm::ArrayType::get(getPtrToType(moduleinfoTy), importInits.size()); importedModules = LLConstantArray::get(importedModulesTy, importInits); } // localClasses[] LLConstant* localClasses = 0; llvm::ArrayType* localClassesTy = 0; ClassDeclarations aclasses; //printf("members->dim = %d\n", members->dim); for (size_t i = 0; i < members->dim; i++) { Dsymbol *member; member = static_cast<Dsymbol *>(members->data[i]); //printf("\tmember '%s'\n", member->toChars()); member->addLocalClass(&aclasses); } // fill inits std::vector<LLConstant*> classInits; for (size_t i = 0; i < aclasses.dim; i++) { ClassDeclaration* cd = static_cast<ClassDeclaration*>(aclasses.data[i]); cd->codegen(Type::sir); if (cd->isInterfaceDeclaration()) { Logger::println("skipping interface '%s' in moduleinfo", cd->toPrettyChars()); continue; } else if (cd->sizeok != 1) { Logger::println("skipping opaque class declaration '%s' in moduleinfo", cd->toPrettyChars()); continue; } Logger::println("class: %s", cd->toPrettyChars()); LLConstant *c = DtoBitCast(cd->ir.irAggr->getClassInfoSymbol(), classinfoTy); classInits.push_back(c); } // has class array? if (!classInits.empty()) { localClassesTy = llvm::ArrayType::get(classinfoTy, classInits.size()); localClasses = LLConstantArray::get(localClassesTy, classInits); } // These must match the values in druntime/src/object_.d #define MIstandalone 4 #define MItlsctor 8 #define MItlsdtor 0x10 #define MIctor 0x20 #define MIdtor 0x40 #define MIxgetMembers 0x80 #define MIictor 0x100 #define MIunitTest 0x200 #define MIimportedModules 0x400 #define MIlocalClasses 0x800 #define MInew 0x80000000 // it's the "new" layout llvm::Function* fsharedctor = build_module_shared_ctor(); llvm::Function* fshareddtor = build_module_shared_dtor(); llvm::Function* funittest = build_module_unittest(); llvm::Function* fctor = build_module_ctor(); llvm::Function* fdtor = build_module_dtor(); unsigned flags = MInew; if (fctor) flags |= MItlsctor; if (fdtor) flags |= MItlsdtor; if (fsharedctor) flags |= MIctor; if (fshareddtor) flags |= MIdtor; #if 0 if (fgetmembers) flags |= MIxgetMembers; if (fictor) flags |= MIictor; #endif if (funittest) flags |= MIunitTest; if (importedModules) flags |= MIimportedModules; if (localClasses) flags |= MIlocalClasses; if (!needmoduleinfo) flags |= MIstandalone; b.push_uint(flags); // flags b.push_uint(0); // index if (fctor) b.push(fctor); if (fdtor) b.push(fdtor); if (fsharedctor) b.push(fsharedctor); if (fshareddtor) b.push(fshareddtor); #if 0 if (fgetmembers) b.push(fgetmembers); if (fictor) b.push(fictor); #endif if (funittest) b.push(funittest); if (importedModules) { b.push_size(importInits.size()); b.push(importedModules); } if (localClasses) { b.push_size(classInits.size()); b.push(localClasses); } // Put out module name as a 0-terminated string. const char *name = toPrettyChars(); const size_t len = strlen(name) + 1; llvm::IntegerType *it = llvm::IntegerType::getInt8Ty(gIR->context()); llvm::ArrayType *at = llvm::ArrayType::get(it, len); b.push(toConstantArray(it, at, name, len, false)); // create and set initializer b.finalize(moduleInfoType, moduleInfoSymbol()); // build the modulereference and ctor for registering it LLFunction* mictor = build_module_reference_and_ctor(moduleInfoSymbol()); AppendFunctionToLLVMGlobalCtorsDtors(mictor, 65535, true); }
llvm::GlobalVariable *genModuleInfo(Module *m) { // check declaration in object.d const auto moduleInfoType = getModuleInfoType(); const auto moduleInfoDecl = Module::moduleinfo; // The "new-style" ModuleInfo records are variable-length, with the presence // of the various fields indicated by a certain flag bit. The base struct // should consist only of the _flags/_index fields (the latter of which is // unused). if (moduleInfoDecl->structsize != 4 + 4) { m->error("Unexpected size of struct `object.ModuleInfo`; " "druntime version does not match compiler (see -v)"); fatal(); } // First, figure out which fields are present and set the flags accordingly. unsigned flags = MInew; const auto fctor = buildModuleCtor(m); if (fctor) { flags |= MItlsctor; } const auto fdtor = buildModuleDtor(m); if (fdtor) { flags |= MItlsdtor; } const auto fsharedctor = buildModuleSharedCtor(m); if (fsharedctor) { flags |= MIctor; } const auto fshareddtor = buildModuleSharedDtor(m); if (fshareddtor) { flags |= MIdtor; } #if 0 if (fgetmembers) flags |= MIxgetMembers; #endif const auto fictor = getIrModule(m)->coverageCtor; if (fictor) flags |= MIictor; const auto funittest = buildModuleUnittest(m); if (funittest) { flags |= MIunitTest; } size_t importedModulesCount; const auto importedModules = buildImportedModules(m, importedModulesCount); if (importedModules) { flags |= MIimportedModules; } size_t localClassesCount; const auto localClasses = buildLocalClasses(m, localClassesCount); if (localClasses) { flags |= MIlocalClasses; } if (!m->needmoduleinfo) { flags |= MIstandalone; } // Now, start building the initialiser for the ModuleInfo instance. RTTIBuilder b(moduleInfoType); b.push_uint(flags); b.push_uint(0); // index if (fctor) { b.push(fctor); } if (fdtor) { b.push(fdtor); } if (fsharedctor) { b.push(fsharedctor); } if (fshareddtor) { b.push(fshareddtor); } #if 0 if (fgetmembers) b.push(fgetmembers); #endif if (fictor) { b.push(fictor); } if (funittest) { b.push(funittest); } if (importedModules) { b.push_size(importedModulesCount); b.push(importedModules); } if (localClasses) { b.push_size(localClassesCount); b.push(localClasses); } // Put out module name as a 0-terminated string. const char *name = m->toPrettyChars(); const size_t len = strlen(name) + 1; const auto it = llvm::IntegerType::getInt8Ty(gIR->context()); const auto at = llvm::ArrayType::get(it, len); b.push(toConstantArray(it, at, name, len, false)); // Create a global symbol with the above initialiser. LLGlobalVariable *moduleInfoSym = getIrModule(m)->moduleInfoSymbol(); b.finalize(moduleInfoSym); setLinkage({LLGlobalValue::ExternalLinkage, supportsCOMDAT()}, moduleInfoSym); return moduleInfoSym; }