void CodeGenVTables::addVTableComponent( ConstantArrayBuilder &builder, const VTableLayout &layout, unsigned idx, llvm::Constant *rtti, unsigned &nextVTableThunkIndex) { auto &component = layout.vtable_components()[idx]; auto addOffsetConstant = [&](CharUnits offset) { builder.add(llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()), CGM.Int8PtrTy)); }; switch (component.getKind()) { case VTableComponent::CK_VCallOffset: return addOffsetConstant(component.getVCallOffset()); case VTableComponent::CK_VBaseOffset: return addOffsetConstant(component.getVBaseOffset()); case VTableComponent::CK_OffsetToTop: return addOffsetConstant(component.getOffsetToTop()); case VTableComponent::CK_RTTI: return builder.add(llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy)); case VTableComponent::CK_FunctionPointer: case VTableComponent::CK_CompleteDtorPointer: case VTableComponent::CK_DeletingDtorPointer: { GlobalDecl GD; // Get the right global decl. switch (component.getKind()) { default: llvm_unreachable("Unexpected vtable component kind"); case VTableComponent::CK_FunctionPointer: GD = component.getFunctionDecl(); break; case VTableComponent::CK_CompleteDtorPointer: GD = GlobalDecl(component.getDestructorDecl(), Dtor_Complete); break; case VTableComponent::CK_DeletingDtorPointer: GD = GlobalDecl(component.getDestructorDecl(), Dtor_Deleting); break; } if (CGM.getLangOpts().CUDA) { // Emit NULL for methods we can't codegen on this // side. Otherwise we'd end up with vtable with unresolved // references. const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); // OK on device side: functions w/ __device__ attribute // OK on host side: anything except __device__-only functions. bool CanEmitMethod = CGM.getLangOpts().CUDAIsDevice ? MD->hasAttr<CUDADeviceAttr>() : (MD->hasAttr<CUDAHostAttr>() || !MD->hasAttr<CUDADeviceAttr>()); if (!CanEmitMethod) return builder.addNullPointer(CGM.Int8PtrTy); // Method is acceptable, continue processing as usual. } auto getSpecialVirtualFn = [&](StringRef name) { llvm::FunctionType *fnTy = llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); llvm::Constant *fn = CGM.CreateRuntimeFunction(fnTy, name); if (auto f = dyn_cast<llvm::Function>(fn)) f->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); return llvm::ConstantExpr::getBitCast(fn, CGM.Int8PtrTy); }; llvm::Constant *fnPtr; // Pure virtual member functions. if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) { if (!PureVirtualFn) PureVirtualFn = getSpecialVirtualFn(CGM.getCXXABI().GetPureVirtualCallName()); fnPtr = PureVirtualFn; // Deleted virtual member functions. } else if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted()) { if (!DeletedVirtualFn) DeletedVirtualFn = getSpecialVirtualFn(CGM.getCXXABI().GetDeletedVirtualCallName()); fnPtr = DeletedVirtualFn; // Thunks. } else if (nextVTableThunkIndex < layout.vtable_thunks().size() && layout.vtable_thunks()[nextVTableThunkIndex].first == idx) { auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second; maybeEmitThunkForVTable(GD, thunkInfo); nextVTableThunkIndex++; fnPtr = CGM.GetAddrOfThunk(GD, thunkInfo); // Otherwise we can use the method definition directly. } else { llvm::Type *fnTy = CGM.getTypes().GetFunctionTypeForVTable(GD); fnPtr = CGM.GetAddrOfFunction(GD, fnTy, /*ForVTable=*/true); } fnPtr = llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy); builder.add(fnPtr); return; } case VTableComponent::CK_UnusedFunctionPointer: return builder.addNullPointer(CGM.Int8PtrTy); } llvm_unreachable("Unexpected vtable component kind"); }
void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable, const VTableLayout &VTLayout) { if (!getCodeGenOpts().LTOUnit) return; CharUnits PointerWidth = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); typedef std::pair<const CXXRecordDecl *, unsigned> AddressPoint; std::vector<AddressPoint> AddressPoints; for (auto &&AP : VTLayout.getAddressPoints()) AddressPoints.push_back(std::make_pair( AP.first.getBase(), VTLayout.getVTableOffset(AP.second.VTableIndex) + AP.second.AddressPointIndex)); // Sort the address points for determinism. llvm::sort(AddressPoints, [this](const AddressPoint &AP1, const AddressPoint &AP2) { if (&AP1 == &AP2) return false; std::string S1; llvm::raw_string_ostream O1(S1); getCXXABI().getMangleContext().mangleTypeName( QualType(AP1.first->getTypeForDecl(), 0), O1); O1.flush(); std::string S2; llvm::raw_string_ostream O2(S2); getCXXABI().getMangleContext().mangleTypeName( QualType(AP2.first->getTypeForDecl(), 0), O2); O2.flush(); if (S1 < S2) return true; if (S1 != S2) return false; return AP1.second < AP2.second; }); ArrayRef<VTableComponent> Comps = VTLayout.vtable_components(); for (auto AP : AddressPoints) { // Create type metadata for the address point. AddVTableTypeMetadata(VTable, PointerWidth * AP.second, AP.first); // The class associated with each address point could also potentially be // used for indirect calls via a member function pointer, so we need to // annotate the address of each function pointer with the appropriate member // function pointer type. for (unsigned I = 0; I != Comps.size(); ++I) { if (Comps[I].getKind() != VTableComponent::CK_FunctionPointer) continue; llvm::Metadata *MD = CreateMetadataIdentifierForVirtualMemPtrType( Context.getMemberPointerType( Comps[I].getFunctionDecl()->getType(), Context.getRecordType(AP.first).getTypePtr())); VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD); } } }