clang API Documentation

ThreadSafetyUtil.h
Go to the documentation of this file.
00001 //===- ThreadSafetyUtil.h --------------------------------------*- C++ --*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file defines some basic utility classes for use by ThreadSafetyTIL.h
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H
00015 #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H
00016 
00017 #include "llvm/ADT/StringRef.h"
00018 #include "llvm/Support/AlignOf.h"
00019 #include "llvm/Support/Allocator.h"
00020 #include "llvm/Support/Compiler.h"
00021 #include "clang/AST/ExprCXX.h"
00022 
00023 #include <cassert>
00024 #include <cstddef>
00025 #include <vector>
00026 #include <utility>
00027 #include <ostream>
00028 
00029 namespace clang {
00030 namespace threadSafety {
00031 namespace til {
00032 
00033 // Simple wrapper class to abstract away from the details of memory management.
00034 // SExprs are allocated in pools, and deallocated all at once.
00035 class MemRegionRef {
00036 private:
00037   union AlignmentType {
00038     double d;
00039     void *p;
00040     long double dd;
00041     long long ii;
00042   };
00043 
00044 public:
00045   MemRegionRef() : Allocator(nullptr) {}
00046   MemRegionRef(llvm::BumpPtrAllocator *A) : Allocator(A) {}
00047 
00048   void *allocate(size_t Sz) {
00049     return Allocator->Allocate(Sz, llvm::AlignOf<AlignmentType>::Alignment);
00050   }
00051 
00052   template <typename T> T *allocateT() { return Allocator->Allocate<T>(); }
00053 
00054   template <typename T> T *allocateT(size_t NumElems) {
00055     return Allocator->Allocate<T>(NumElems);
00056   }
00057 
00058 private:
00059   llvm::BumpPtrAllocator *Allocator;
00060 };
00061 
00062 
00063 } // end namespace til
00064 } // end namespace threadSafety
00065 } // end namespace clang
00066 
00067 
00068 inline void *operator new(size_t Sz,
00069                           clang::threadSafety::til::MemRegionRef &R) {
00070   return R.allocate(Sz);
00071 }
00072 
00073 
00074 namespace clang {
00075 namespace threadSafety {
00076 
00077 std::string getSourceLiteralString(const clang::Expr *CE);
00078 
00079 using llvm::StringRef;
00080 using clang::SourceLocation;
00081 
00082 namespace til {
00083 
00084 
00085 // A simple fixed size array class that does not manage its own memory,
00086 // suitable for use with bump pointer allocation.
00087 template <class T> class SimpleArray {
00088 public:
00089   SimpleArray() : Data(nullptr), Size(0), Capacity(0) {}
00090   SimpleArray(T *Dat, size_t Cp, size_t Sz = 0)
00091       : Data(Dat), Size(Sz), Capacity(Cp) {}
00092   SimpleArray(MemRegionRef A, size_t Cp)
00093       : Data(Cp == 0 ? nullptr : A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {}
00094   SimpleArray(SimpleArray<T> &&A)
00095       : Data(A.Data), Size(A.Size), Capacity(A.Capacity) {
00096     A.Data = nullptr;
00097     A.Size = 0;
00098     A.Capacity = 0;
00099   }
00100 
00101   SimpleArray &operator=(SimpleArray &&RHS) {
00102     if (this != &RHS) {
00103       Data = RHS.Data;
00104       Size = RHS.Size;
00105       Capacity = RHS.Capacity;
00106 
00107       RHS.Data = nullptr;
00108       RHS.Size = RHS.Capacity = 0;
00109     }
00110     return *this;
00111   }
00112 
00113   // Reserve space for at least Ncp items, reallocating if necessary.
00114   void reserve(size_t Ncp, MemRegionRef A) {
00115     if (Ncp <= Capacity)
00116       return;
00117     T *Odata = Data;
00118     Data = A.allocateT<T>(Ncp);
00119     Capacity = Ncp;
00120     memcpy(Data, Odata, sizeof(T) * Size);
00121     return;
00122   }
00123 
00124   // Reserve space for at least N more items.
00125   void reserveCheck(size_t N, MemRegionRef A) {
00126     if (Capacity == 0)
00127       reserve(u_max(InitialCapacity, N), A);
00128     else if (Size + N < Capacity)
00129       reserve(u_max(Size + N, Capacity * 2), A);
00130   }
00131 
00132   typedef T *iterator;
00133   typedef const T *const_iterator;
00134 
00135   size_t size() const { return Size; }
00136   size_t capacity() const { return Capacity; }
00137 
00138   T &operator[](unsigned i) {
00139     assert(i < Size && "Array index out of bounds.");
00140     return Data[i];
00141   }
00142   const T &operator[](unsigned i) const {
00143     assert(i < Size && "Array index out of bounds.");
00144     return Data[i];
00145   }
00146   T &back() {
00147     assert(Size && "No elements in the array.");
00148     return Data[Size - 1];
00149   }
00150   const T &back() const {
00151     assert(Size && "No elements in the array.");
00152     return Data[Size - 1];
00153   }
00154 
00155   iterator begin() { return Data; }
00156   iterator end()   { return Data + Size; }
00157 
00158   const_iterator begin() const { return Data; }
00159   const_iterator end()   const { return Data + Size; }
00160 
00161   const_iterator cbegin() const { return Data; }
00162   const_iterator cend()   const { return Data + Size; }
00163 
00164   void push_back(const T &Elem) {
00165     assert(Size < Capacity);
00166     Data[Size++] = Elem;
00167   }
00168 
00169   // drop last n elements from array
00170   void drop(unsigned n = 0) {
00171     assert(Size > n);
00172     Size -= n;
00173   }
00174 
00175   void setValues(unsigned Sz, const T& C) {
00176     assert(Sz <= Capacity);
00177     Size = Sz;
00178     for (unsigned i = 0; i < Sz; ++i) {
00179       Data[i] = C;
00180     }
00181   }
00182 
00183   template <class Iter> unsigned append(Iter I, Iter E) {
00184     size_t Osz = Size;
00185     size_t J = Osz;
00186     for (; J < Capacity && I != E; ++J, ++I)
00187       Data[J] = *I;
00188     Size = J;
00189     return J - Osz;
00190   }
00191 
00192   // An adaptor to reverse a simple array
00193   class ReverseAdaptor {
00194    public:
00195     ReverseAdaptor(SimpleArray &Array) : Array(Array) {}
00196     // A reverse iterator used by the reverse adaptor
00197     class Iterator {
00198      public:
00199       Iterator(T *Data) : Data(Data) {}
00200       T &operator*() { return *Data; }
00201       const T &operator*() const { return *Data; }
00202       Iterator &operator++() {
00203         --Data;
00204         return *this;
00205       }
00206       bool operator!=(Iterator Other) { return Data != Other.Data; }
00207 
00208      private:
00209       T *Data;
00210     };
00211     Iterator begin() { return Array.end() - 1; }
00212     Iterator end() { return Array.begin() - 1; }
00213     const Iterator begin() const { return Array.end() - 1; }
00214     const Iterator end() const { return Array.begin() - 1; }
00215 
00216    private:
00217     SimpleArray &Array;
00218   };
00219 
00220   const ReverseAdaptor reverse() const { return ReverseAdaptor(*this); }
00221   ReverseAdaptor reverse() { return ReverseAdaptor(*this); }
00222 
00223 private:
00224   // std::max is annoying here, because it requires a reference,
00225   // thus forcing InitialCapacity to be initialized outside the .h file.
00226   size_t u_max(size_t i, size_t j) { return (i < j) ? j : i; }
00227 
00228   static const size_t InitialCapacity = 4;
00229 
00230   SimpleArray(const SimpleArray<T> &A) LLVM_DELETED_FUNCTION;
00231 
00232   T *Data;
00233   size_t Size;
00234   size_t Capacity;
00235 };
00236 
00237 
00238 }  // end namespace til
00239 
00240 
00241 // A copy on write vector.
00242 // The vector can be in one of three states:
00243 // * invalid -- no operations are permitted.
00244 // * read-only -- read operations are permitted.
00245 // * writable -- read and write operations are permitted.
00246 // The init(), destroy(), and makeWritable() methods will change state.
00247 template<typename T>
00248 class CopyOnWriteVector {
00249   class VectorData {
00250   public:
00251     VectorData() : NumRefs(1) { }
00252     VectorData(const VectorData &VD) : NumRefs(1), Vect(VD.Vect) { }
00253 
00254     unsigned NumRefs;
00255     std::vector<T> Vect;
00256   };
00257 
00258   // No copy constructor or copy assignment.  Use clone() with move assignment.
00259   CopyOnWriteVector(const CopyOnWriteVector &V) LLVM_DELETED_FUNCTION;
00260   void operator=(const CopyOnWriteVector &V) LLVM_DELETED_FUNCTION;
00261 
00262 public:
00263   CopyOnWriteVector() : Data(nullptr) {}
00264   CopyOnWriteVector(CopyOnWriteVector &&V) : Data(V.Data) { V.Data = nullptr; }
00265   ~CopyOnWriteVector() { destroy(); }
00266 
00267   // Returns true if this holds a valid vector.
00268   bool valid() const  { return Data; }
00269 
00270   // Returns true if this vector is writable.
00271   bool writable() const { return Data && Data->NumRefs == 1; }
00272 
00273   // If this vector is not valid, initialize it to a valid vector.
00274   void init() {
00275     if (!Data) {
00276       Data = new VectorData();
00277     }
00278   }
00279 
00280   // Destroy this vector; thus making it invalid.
00281   void destroy() {
00282     if (!Data)
00283       return;
00284     if (Data->NumRefs <= 1)
00285       delete Data;
00286     else
00287       --Data->NumRefs;
00288     Data = nullptr;
00289   }
00290 
00291   // Make this vector writable, creating a copy if needed.
00292   void makeWritable() {
00293     if (!Data) {
00294       Data = new VectorData();
00295       return;
00296     }
00297     if (Data->NumRefs == 1)
00298       return;   // already writeable.
00299     --Data->NumRefs;
00300     Data = new VectorData(*Data);
00301   }
00302 
00303   // Create a lazy copy of this vector.
00304   CopyOnWriteVector clone() { return CopyOnWriteVector(Data); }
00305 
00306   CopyOnWriteVector &operator=(CopyOnWriteVector &&V) {
00307     destroy();
00308     Data = V.Data;
00309     V.Data = nullptr;
00310     return *this;
00311   }
00312 
00313   typedef typename std::vector<T>::const_iterator const_iterator;
00314 
00315   const std::vector<T> &elements() const { return Data->Vect; }
00316 
00317   const_iterator begin() const { return elements().cbegin(); }
00318   const_iterator end() const { return elements().cend(); }
00319 
00320   const T& operator[](unsigned i) const { return elements()[i]; }
00321 
00322   unsigned size() const { return Data ? elements().size() : 0; }
00323 
00324   // Return true if V and this vector refer to the same data.
00325   bool sameAs(const CopyOnWriteVector &V) const { return Data == V.Data; }
00326 
00327   // Clear vector.  The vector must be writable.
00328   void clear() {
00329     assert(writable() && "Vector is not writable!");
00330     Data->Vect.clear();
00331   }
00332 
00333   // Push a new element onto the end.  The vector must be writable.
00334   void push_back(const T &Elem) {
00335     assert(writable() && "Vector is not writable!");
00336     Data->Vect.push_back(Elem);
00337   }
00338 
00339   // Gets a mutable reference to the element at index(i).
00340   // The vector must be writable.
00341   T& elem(unsigned i) {
00342     assert(writable() && "Vector is not writable!");
00343     return Data->Vect[i];
00344   }
00345 
00346   // Drops elements from the back until the vector has size i.
00347   void downsize(unsigned i) {
00348     assert(writable() && "Vector is not writable!");
00349     Data->Vect.erase(Data->Vect.begin() + i, Data->Vect.end());
00350   }
00351 
00352 private:
00353   CopyOnWriteVector(VectorData *D) : Data(D) {
00354     if (!Data)
00355       return;
00356     ++Data->NumRefs;
00357   }
00358 
00359   VectorData *Data;
00360 };
00361 
00362 
00363 inline std::ostream& operator<<(std::ostream& ss, const StringRef str) {
00364   return ss.write(str.data(), str.size());
00365 }
00366 
00367 
00368 } // end namespace threadSafety
00369 } // end namespace clang
00370 
00371 #endif  // LLVM_CLANG_THREAD_SAFETY_UTIL_H