// what a hack static Function *getStubFunctionForCtorList(Module *m, GlobalVariable *gv, std::string name) { assert(!gv->isDeclaration() && !gv->hasInternalLinkage() && "do not support old LLVM style constructor/destructor lists"); std::vector<Type *> nullary; Function *fn = Function::Create(FunctionType::get(Type::getVoidTy(m->getContext()), nullary, false), GlobalVariable::InternalLinkage, name, m); BasicBlock *bb = BasicBlock::Create(m->getContext(), "entry", fn); // From lli: // Should be an array of '{ int, void ()* }' structs. The first value is // the init priority, which we ignore. ConstantArray *arr = dyn_cast<ConstantArray>(gv->getInitializer()); if (arr) { for (unsigned i=0; i<arr->getNumOperands(); i++) { ConstantStruct *cs = cast<ConstantStruct>(arr->getOperand(i)); #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) // There is a third *optional* element in global_ctor elements (``i8 // @data``). assert((cs->getNumOperands() == 2 || cs->getNumOperands() == 3) && "unexpected element in ctor initializer list"); #else assert(cs->getNumOperands()==2 && "unexpected element in ctor initializer list"); #endif Constant *fp = cs->getOperand(1); if (!fp->isNullValue()) { if (llvm::ConstantExpr *ce = dyn_cast<llvm::ConstantExpr>(fp)) fp = ce->getOperand(0); if (Function *f = dyn_cast<Function>(fp)) { CallInst::Create(f, "", bb); } else { assert(0 && "unable to get function pointer from ctor initializer list"); } } } } ReturnInst::Create(m->getContext(), bb); return fn; }
CtorDtorIterator::Element CtorDtorIterator::operator*() const { ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(I)); assert(CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors"); Constant *FuncC = CS->getOperand(1); Function *Func = nullptr; // Extract function pointer, pulling off any casts. while (FuncC) { if (Function *F = dyn_cast_or_null<Function>(FuncC)) { Func = F; break; } else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(FuncC)) { if (CE->isCast()) FuncC = dyn_cast_or_null<ConstantExpr>(CE->getOperand(0)); else break; } else { // This isn't anything we recognize. Bail out with Func left set to null. break; } } ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0)); Value *Data = CS->getNumOperands() == 3 ? CS->getOperand(2) : nullptr; if (Data && !isa<GlobalValue>(Data)) Data = nullptr; return Element(Priority->getZExtValue(), Func, Data); }
void ClassHierarchyUtils::processTypeInfo(GlobalVariable* TI) { if (find(classes.begin(), classes.end(), TI) == classes.end()) { classes.push_back(TI); // extract direct base classes from type_info if (TI->hasInitializer()) { ConstantStruct* TIinit = cast<ConstantStruct>(TI->getInitializer()); int TInumOperands = TIinit->getNumOperands(); if (TInumOperands > 2) { // we have >= 1 base class(es). if (TInumOperands == 3) { // abi::__si_class_type_info GlobalVariable* baseTI = cast<GlobalVariable>(TIinit->getOperand(2)->stripPointerCasts()); classToSubclasses[baseTI].push_back(TI); //dbgs() << " " << *baseTI << "\n"; classToBaseOffset[TI][baseTI] = 0; processTypeInfo(baseTI); } else { // abi::__vmi_class_type_info // (skip over first two additional fields, which are "flags" and "base_count") for (int i=4; i<TInumOperands; i+=2) { GlobalVariable* baseTI = cast<GlobalVariable>(TIinit->getOperand(i)->stripPointerCasts()); classToSubclasses[baseTI].push_back(TI); int offset_flags = cast<ConstantInt>(TIinit->getOperand(i+1))->getSExtValue(); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << TI->getName() << " -> " << baseTI->getName() << "\n"); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << " offset_flags = " << offset_flags << "\n"); int offset = offset_flags >> 8; // TODO: is this value defined as a constant somewhere? SDEBUG("soaap.util.classhierarchy", 3, dbgs() << " offset = " << offset << "\n"); classToBaseOffset[TI][baseTI] = offset; //dbgs() << " " << *baseTI << "\n"; processTypeInfo(baseTI); } } } }
void MemoryInstrumenter::lowerGlobalCtors(Module &M) { // Find llvm.global_ctors. GlobalVariable *GV = M.getNamedGlobal("llvm.global_ctors"); if (!GV) return; assert(!GV->isDeclaration() && !GV->hasLocalLinkage()); // Should be an array of '{ int, void ()* }' structs. The first value is // the init priority, which must be 65535 if the bitcode is generated using // clang. if (ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer())) { for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i)); assert(CS); assert(CS->getNumOperands() == 2); // Get the priority. ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0)); assert(Priority); // TODO: For now, we assume all priorities must be 65535. assert(Priority->equalsInt(65535)); // Get the constructor function. Constant *FP = CS->getOperand(1); if (FP->isNullValue()) break; // Found a null terminator, exit. // Explicitly call the constructor at the main entry. CallInst::Create(FP, "", Main->begin()->getFirstNonPHI()); } } // Clear the global_ctors array. // Use eraseFromParent() instead of removeFromParent(). GV->eraseFromParent(); }
void ClassHierarchyUtils::processTypeInfo(GlobalVariable* TI, Module& M) { if (find(classes.begin(), classes.end(), TI) == classes.end()) { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Adding class " << TI->getName() << "\n"); classes.push_back(TI); // First process the correspoding virtual table. We store the indexes of the primary // and secondary vtables, indexed by the corresponding subobject offset. This will allow // us to quickly jump to a particular sub-vtable. if (typeInfoToVTable.find(TI) != typeInfoToVTable.end()) { GlobalVariable* VT = typeInfoToVTable[TI]; SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Found vtable: " << VT->getName() << "\n"); ConstantStruct* VTinit = cast<ConstantStruct>(VT->getInitializer()); for (int i=0; i<VTinit->getNumOperands(); i++) { ConstantArray* VTinitElem = cast<ConstantArray>(VTinit->getOperand(i)); for (int j=0; j<VTinitElem->getNumOperands(); j++) { // Each sub-vtable is preceded by a reference to the class's type_info instance. // (See https://mentorembedded.github.io/cxx-abi/abi.html). if (TI == VTinitElem->getOperand(j)->stripPointerCasts()) { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Found TI at index " << i << "\n"); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "Storing mapping " << VT->getName() << " <-> " << TI->getName() << "\n"); // the offset to top is the offset from the vptr pointing to this // sub-vtable, back to the top of the object. This will be negative, // but the absolute value gives us the offset from the start of the // object (i.e. first vptr), to the subobject. int offsetToTop = 0; if (ConstantExpr* offsetValCast = dyn_cast<ConstantExpr>(VTinitElem->getOperand(j-1)->stripPointerCasts())) { ConstantInt* offsetVal = cast<ConstantInt>(offsetValCast->getOperand(0)); offsetToTop = offsetVal->getSExtValue(); // will be 0 for the primary } if (offsetToTop > 0) { report_fatal_error("ERROR: offsetToTop is positive!"); } else { offsetToTop *= -1; } SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "offsetToTop: " << offsetToTop << "\n") vTableToSecondaryVTableMaps[VT][offsetToTop] = pair<int, int>(i, j+1); } } } } else { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "No vtable found for " << TI->getName() << "\n"); } // Now process the type_info struct, extract direct base class info (what // their subobject offsets are, or if they are virtual then their // virtual-base-offset-offset) if (TI->hasInitializer()) { ConstantStruct* TIinit = cast<ConstantStruct>(TI->getInitializer()); int TInumOperands = TIinit->getNumOperands(); if (TInumOperands > 2) { // first two operands are vptr and type name // we have >= 1 base class(es). if (TInumOperands == 3) { // abi::__si_class_type_info: single, public, non-virtual base at // offset 0 SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "abi::__si_class_type_info\n"); GlobalVariable* baseTI = cast<GlobalVariable>(TIinit->getOperand(2)->stripPointerCasts()); classToSubclasses[baseTI].push_back(TI); //dbgs() << " " << *baseTI << "\n"; classToBaseOffset[TI][baseTI] = 0; processTypeInfo(baseTI, M); } else { // abi::__vmi_class_type_info: all other cases SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "abi::__vmi_class_type_info\n"); // (skip over first two additional fields, which are "flags" and "base_count") for (int i=4; i<TInumOperands; i+=2) { GlobalVariable* baseTI = cast<GlobalVariable>(TIinit->getOperand(i)->stripPointerCasts()); classToSubclasses[baseTI].push_back(TI); long offset_flags = cast<ConstantInt>(TIinit->getOperand(i+1))->getSExtValue(); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << TI->getName() << " -> " << baseTI->getName() << "\n"); SDEBUG("soaap.util.classhierarchy", 3, dbgs() << " offset_flags = " << offset_flags << "\n"); ptrdiff_t offset = offset_flags >> offset_shift; SDEBUG("soaap.util.classhierarchy", 3, dbgs() << " offset = " << offset << "\n"); // If this a virtual base class, then we obtain the // vbase-offset-offset. This is the offset from the start of the // derived class's (primary) vtable to the location containing the // vbase-offset, which is the offset from the start of the object // to the virtual base's subobject. Note that virtual base // subobjects only exist once and are laid out after all other // non-virtual objects. We keep track of the vbase-offset-offset, // so that we can find the vbase offset when going down the class // hierarchy. (The vbase offset may differ every time but the // vbase-offset-offset will remain the same relative to the current // class's vtable in subclasses). if (offset_flags & virtual_mask) { // is this a virtual base class? SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "virtual base class: " << baseTI->getName() << "\n"); int vbaseOffsetOffset = offset/sizeof(long); // this should be negative SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "vbase-offset-offset: " << vbaseOffsetOffset << "\n"); classToVBaseOffsetOffset[TI][baseTI] = vbaseOffsetOffset; if (typeInfoToVTable.find(TI) != typeInfoToVTable.end()) { GlobalVariable* VT = typeInfoToVTable[TI]; int vbaseOffsetIdx = vTableToSecondaryVTableMaps[VT][0].second+vbaseOffsetOffset; SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "vbase-offset-idx: " << vbaseOffsetIdx << "\n"); } else { SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "No VTable for " << TI->getName() << "\n"); } } else { // In the non-virtual base class case, we just record the subobj // offset. This is the offset from the start of the derived // object to the base class's subobject. We use this information // together with the offset-to-top info we obtained from the // vtable to find the base class's subvtable. Note that the // relative position of the base class subobj within the current // derived object will always remain the same, even in // subclasses. classToBaseOffset[TI][baseTI] = offset; } //dbgs() << " " << *baseTI << "\n"; processTypeInfo(baseTI, M); } } } }
/// analyzeDestructor - Given the heap.metadata argument to swift_allocObject, /// take a look a the destructor and try to decide if it has side effects or any /// other bad effects that can prevent it from being optimized. static DtorKind analyzeDestructor(Value *P) { // If we have a null pointer for the metadata info, the dtor has no side // effects. Actually, the final release would crash. This is really only // useful for writing testcases. if (isa<ConstantPointerNull>(P->stripPointerCasts())) return DtorKind::NoSideEffects; // We have to have a known heap metadata value, reject dynamically computed // ones, or places GlobalVariable *GV = dyn_cast<GlobalVariable>(P->stripPointerCasts()); if (GV == 0 || GV->mayBeOverridden()) return DtorKind::Unknown; ConstantStruct *CS = dyn_cast_or_null<ConstantStruct>(GV->getInitializer()); if (CS == 0 || CS->getNumOperands() == 0) return DtorKind::Unknown; // FIXME: Would like to abstract the dtor slot (#0) out from this to somewhere // unified. enum { DTorSlotOfHeapMetadata = 0 }; Function *DtorFn =dyn_cast<Function>(CS->getOperand(DTorSlotOfHeapMetadata)); if (DtorFn == 0 || DtorFn->mayBeOverridden() || DtorFn->hasExternalLinkage()) return DtorKind::Unknown; // Okay, we have a body, and we can trust it. If the function is marked // readonly, then we know it can't have any interesting side effects, so we // don't need to analyze it at all. if (DtorFn->onlyReadsMemory()) return DtorKind::NoSideEffects; // The first argument is the object being destroyed. assert(DtorFn->arg_size() == 1 && !DtorFn->isVarArg() && "expected a single object argument to destructors"); Value *ThisObject = &*DtorFn->arg_begin(); // Scan the body of the function, looking for anything scary. for (BasicBlock &BB : *DtorFn) { for (Instruction &I : BB) { // Note that the destructor may not be in any particular canonical form. switch (classifyInstruction(I)) { // These instructions should not reach here based on the pass ordering. // i.e. LLVMARCOpt -> LLVMContractOpt. case RT_RetainN: case RT_UnknownRetainN: case RT_BridgeRetainN: case RT_ReleaseN: case RT_UnknownReleaseN: case RT_BridgeReleaseN: llvm_unreachable("These are only created by LLVMARCContract !"); case RT_NoMemoryAccessed: case RT_AllocObject: case RT_FixLifetime: case RT_CheckUnowned: // Skip over random instructions that don't touch memory in the caller. continue; case RT_RetainUnowned: case RT_BridgeRetain: // x = swift_bridgeRetain(y) case RT_Retain: { // swift_retain(obj) // Ignore retains of the "self" object, no resurrection is possible. Value *ThisRetainedObject = cast<CallInst>(I).getArgOperand(0); if (ThisRetainedObject->stripPointerCasts() == ThisObject->stripPointerCasts()) continue; // Otherwise, we may be retaining something scary. break; } case RT_Release: { // If we get to a release that is provably to this object, then we can // ignore it. Value *ThisReleasedObject = cast<CallInst>(I).getArgOperand(0); if (ThisReleasedObject->stripPointerCasts() == ThisObject->stripPointerCasts()) continue; // Otherwise, we may be retaining something scary. break; } case RT_ObjCRelease: case RT_ObjCRetain: case RT_UnknownRetain: case RT_UnknownRelease: case RT_BridgeRelease: // Objective-C retain and release can have arbitrary side effects. break; case RT_Unknown: // Ignore all instructions with no side effects. if (!I.mayHaveSideEffects()) continue; // store, memcpy, memmove *to* the object can be dropped. if (StoreInst *SI = dyn_cast<StoreInst>(&I)) { if (SI->getPointerOperand()->stripInBoundsOffsets() == ThisObject) continue; } if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(&I)) { if (MI->getDest()->stripInBoundsOffsets() == ThisObject) continue; } // Otherwise, we can't remove the deallocation completely. break; } // Okay, the function has some side effects, if it doesn't capture the // object argument, at least that is something. return DtorFn->doesNotCapture(0) ? DtorKind::NoEscape : DtorKind::Unknown; } } // If we didn't find any side effects, we win. return DtorKind::NoSideEffects; }