Home | History | Annotate | Download | only in src
      1 //===-------------------------- debug.cpp ---------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #define _LIBCPP_DEBUG 1
     11 #include "__config"
     12 #include "__debug"
     13 #include "functional"
     14 #include "algorithm"
     15 #include "__hash_table"
     16 #include "mutex"
     17 
     18 _LIBCPP_BEGIN_NAMESPACE_STD
     19 
     20 _LIBCPP_FUNC_VIS
     21 __libcpp_db*
     22 __get_db()
     23 {
     24     static __libcpp_db db;
     25     return &db;
     26 }
     27 
     28 _LIBCPP_FUNC_VIS
     29 const __libcpp_db*
     30 __get_const_db()
     31 {
     32     return __get_db();
     33 }
     34 
     35 namespace
     36 {
     37 
     38 #ifndef _LIBCPP_HAS_NO_THREADS
     39 typedef mutex mutex_type;
     40 typedef lock_guard<mutex_type> WLock;
     41 typedef lock_guard<mutex_type> RLock;
     42 
     43 mutex_type&
     44 mut()
     45 {
     46     static mutex_type m;
     47     return m;
     48 }
     49 #endif // !_LIBCPP_HAS_NO_THREADS
     50 
     51 }  // unnamed namespace
     52 
     53 __i_node::~__i_node()
     54 {
     55     if (__next_)
     56     {
     57         __next_->~__i_node();
     58         free(__next_);
     59     }
     60 }
     61 
     62 __c_node::~__c_node()
     63 {
     64     free(beg_);
     65     if (__next_)
     66     {
     67         __next_->~__c_node();
     68         free(__next_);
     69     }
     70 }
     71 
     72 __libcpp_db::__libcpp_db()
     73     : __cbeg_(nullptr),
     74       __cend_(nullptr),
     75       __csz_(0),
     76       __ibeg_(nullptr),
     77       __iend_(nullptr),
     78       __isz_(0)
     79 {
     80 }
     81 
     82 __libcpp_db::~__libcpp_db()
     83 {
     84     if (__cbeg_)
     85     {
     86         for (__c_node** p = __cbeg_; p != __cend_; ++p)
     87         {
     88             if (*p != nullptr)
     89             {
     90                 (*p)->~__c_node();
     91                 free(*p);
     92             }
     93         }
     94         free(__cbeg_);
     95     }
     96     if (__ibeg_)
     97     {
     98         for (__i_node** p = __ibeg_; p != __iend_; ++p)
     99         {
    100             if (*p != nullptr)
    101             {
    102                 (*p)->~__i_node();
    103                 free(*p);
    104             }
    105         }
    106         free(__ibeg_);
    107     }
    108 }
    109 
    110 void*
    111 __libcpp_db::__find_c_from_i(void* __i) const
    112 {
    113 #ifndef _LIBCPP_HAS_NO_THREADS
    114     RLock _(mut());
    115 #endif
    116     __i_node* i = __find_iterator(__i);
    117     _LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database.");
    118     return i->__c_ != nullptr ? i->__c_->__c_ : nullptr;
    119 }
    120 
    121 void
    122 __libcpp_db::__insert_ic(void* __i, const void* __c)
    123 {
    124 #ifndef _LIBCPP_HAS_NO_THREADS
    125     WLock _(mut());
    126 #endif
    127     if (__cbeg_ == __cend_)
    128         return;
    129     size_t hc = hash<const void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
    130     __c_node* c = __cbeg_[hc];
    131     if (c == nullptr)
    132         return;
    133     while (c->__c_ != __c)
    134     {
    135         c = c->__next_;
    136         if (c == nullptr)
    137             return;
    138     }
    139     __i_node* i = __insert_iterator(__i);
    140     c->__add(i);
    141     i->__c_ = c;
    142 }
    143 
    144 __c_node*
    145 __libcpp_db::__insert_c(void* __c)
    146 {
    147 #ifndef _LIBCPP_HAS_NO_THREADS
    148     WLock _(mut());
    149 #endif
    150     if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_))
    151     {
    152         size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1);
    153         __c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(void*)));
    154         if (cbeg == nullptr)
    155 #ifndef _LIBCPP_NO_EXCEPTIONS
    156             throw bad_alloc();
    157 #else
    158             abort();
    159 #endif
    160         for (__c_node** p = __cbeg_; p != __cend_; ++p)
    161         {
    162             __c_node* q = *p;
    163             while (q != nullptr)
    164             {
    165                 size_t h = hash<void*>()(q->__c_) % nc;
    166                 __c_node* r = q->__next_;
    167                 q->__next_ = cbeg[h];
    168                 cbeg[h] = q;
    169                 q = r;
    170             }
    171         }
    172         free(__cbeg_);
    173         __cbeg_ = cbeg;
    174         __cend_ = __cbeg_ + nc;
    175     }
    176     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
    177     __c_node* p = __cbeg_[hc];
    178     __c_node* r = __cbeg_[hc] =
    179       static_cast<__c_node*>(malloc(sizeof(__c_node)));
    180     if (__cbeg_[hc] == nullptr)
    181 #ifndef _LIBCPP_NO_EXCEPTIONS
    182         throw bad_alloc();
    183 #else
    184         abort();
    185 #endif
    186     r->__c_ = __c;
    187     r->__next_ = p;
    188     ++__csz_;
    189     return r;
    190 }
    191 
    192 void
    193 __libcpp_db::__erase_i(void* __i)
    194 {
    195 #ifndef _LIBCPP_HAS_NO_THREADS
    196     WLock _(mut());
    197 #endif
    198     if (__ibeg_ != __iend_)
    199     {
    200         size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
    201         __i_node* p = __ibeg_[hi];
    202         if (p != nullptr)
    203         {
    204             __i_node* q = nullptr;
    205             while (p->__i_ != __i)
    206             {
    207                 q = p;
    208                 p = p->__next_;
    209                 if (p == nullptr)
    210                     return;
    211             }
    212             if (q == nullptr)
    213                 __ibeg_[hi] = p->__next_;
    214             else
    215                 q->__next_ = p->__next_;
    216             __c_node* c = p->__c_;
    217             --__isz_;
    218             if (c != nullptr)
    219                 c->__remove(p);
    220             free(p);
    221         }
    222     }
    223 }
    224 
    225 void
    226 __libcpp_db::__invalidate_all(void* __c)
    227 {
    228 #ifndef _LIBCPP_HAS_NO_THREADS
    229     WLock _(mut());
    230 #endif
    231     if (__cend_ != __cbeg_)
    232     {
    233         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
    234         __c_node* p = __cbeg_[hc];
    235         if (p == nullptr)
    236             return;
    237         while (p->__c_ != __c)
    238         {
    239             p = p->__next_;
    240             if (p == nullptr)
    241                 return;
    242         }
    243         while (p->end_ != p->beg_)
    244         {
    245             --p->end_;
    246             (*p->end_)->__c_ = nullptr;
    247         }
    248     }
    249 }
    250 
    251 __c_node*
    252 __libcpp_db::__find_c_and_lock(void* __c) const
    253 {
    254 #ifndef _LIBCPP_HAS_NO_THREADS
    255     mut().lock();
    256 #endif
    257     if (__cend_ == __cbeg_)
    258     {
    259 #ifndef _LIBCPP_HAS_NO_THREADS
    260         mut().unlock();
    261 #endif
    262         return nullptr;
    263     }
    264     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
    265     __c_node* p = __cbeg_[hc];
    266     if (p == nullptr)
    267     {
    268 #ifndef _LIBCPP_HAS_NO_THREADS
    269         mut().unlock();
    270 #endif
    271         return nullptr;
    272     }
    273     while (p->__c_ != __c)
    274     {
    275         p = p->__next_;
    276         if (p == nullptr)
    277         {
    278 #ifndef _LIBCPP_HAS_NO_THREADS
    279             mut().unlock();
    280 #endif
    281             return nullptr;
    282         }
    283     }
    284     return p;
    285 }
    286 
    287 __c_node*
    288 __libcpp_db::__find_c(void* __c) const
    289 {
    290     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
    291     __c_node* p = __cbeg_[hc];
    292     _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A");
    293     while (p->__c_ != __c)
    294     {
    295         p = p->__next_;
    296         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B");
    297     }
    298     return p;
    299 }
    300 
    301 void
    302 __libcpp_db::unlock() const
    303 {
    304 #ifndef _LIBCPP_HAS_NO_THREADS
    305     mut().unlock();
    306 #endif
    307 }
    308 
    309 void
    310 __libcpp_db::__erase_c(void* __c)
    311 {
    312 #ifndef _LIBCPP_HAS_NO_THREADS
    313     WLock _(mut());
    314 #endif
    315     if (__cend_ != __cbeg_)
    316     {
    317         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
    318         __c_node* p = __cbeg_[hc];
    319         if (p == nullptr)
    320             return;
    321         __c_node* q = nullptr;
    322         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
    323         while (p->__c_ != __c)
    324         {
    325             q = p;
    326             p = p->__next_;
    327             if (p == nullptr)
    328                 return;
    329             _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
    330         }
    331         if (q == nullptr)
    332             __cbeg_[hc] = p->__next_;
    333         else
    334             q->__next_ = p->__next_;
    335         while (p->end_ != p->beg_)
    336         {
    337             --p->end_;
    338             (*p->end_)->__c_ = nullptr;
    339         }
    340         free(p->beg_);
    341         free(p);
    342         --__csz_;
    343     }
    344 }
    345 
    346 void
    347 __libcpp_db::__iterator_copy(void* __i, const void* __i0)
    348 {
    349 #ifndef _LIBCPP_HAS_NO_THREADS
    350     WLock _(mut());
    351 #endif
    352     __i_node* i = __find_iterator(__i);
    353     __i_node* i0 = __find_iterator(__i0);
    354     __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
    355     if (i == nullptr && i0 != nullptr)
    356         i = __insert_iterator(__i);
    357     __c_node* c = i != nullptr ? i->__c_ : nullptr;
    358     if (c != c0)
    359     {
    360         if (c != nullptr)
    361             c->__remove(i);
    362         if (i != nullptr)
    363         {
    364             i->__c_ = nullptr;
    365             if (c0 != nullptr)
    366             {
    367                 i->__c_ = c0;
    368                 i->__c_->__add(i);
    369             }
    370         }
    371     }
    372 }
    373 
    374 bool
    375 __libcpp_db::__dereferenceable(const void* __i) const
    376 {
    377 #ifndef _LIBCPP_HAS_NO_THREADS
    378     RLock _(mut());
    379 #endif
    380     __i_node* i = __find_iterator(__i);
    381     return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
    382 }
    383 
    384 bool
    385 __libcpp_db::__decrementable(const void* __i) const
    386 {
    387 #ifndef _LIBCPP_HAS_NO_THREADS
    388     RLock _(mut());
    389 #endif
    390     __i_node* i = __find_iterator(__i);
    391     return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
    392 }
    393 
    394 bool
    395 __libcpp_db::__addable(const void* __i, ptrdiff_t __n) const
    396 {
    397 #ifndef _LIBCPP_HAS_NO_THREADS
    398     RLock _(mut());
    399 #endif
    400     __i_node* i = __find_iterator(__i);
    401     return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n);
    402 }
    403 
    404 bool
    405 __libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
    406 {
    407 #ifndef _LIBCPP_HAS_NO_THREADS
    408     RLock _(mut());
    409 #endif
    410     __i_node* i = __find_iterator(__i);
    411     return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
    412 }
    413 
    414 bool
    415 __libcpp_db::__less_than_comparable(const void* __i, const void* __j) const
    416 {
    417 #ifndef _LIBCPP_HAS_NO_THREADS
    418     RLock _(mut());
    419 #endif
    420     __i_node* i = __find_iterator(__i);
    421     __i_node* j = __find_iterator(__j);
    422     __c_node* ci = i != nullptr ? i->__c_ : nullptr;
    423     __c_node* cj = j != nullptr ? j->__c_ : nullptr;
    424     return ci != nullptr && ci == cj;
    425 }
    426 
    427 void
    428 __libcpp_db::swap(void* c1, void* c2)
    429 {
    430 #ifndef _LIBCPP_HAS_NO_THREADS
    431     WLock _(mut());
    432 #endif
    433     size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_);
    434     __c_node* p1 = __cbeg_[hc];
    435     _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
    436     while (p1->__c_ != c1)
    437     {
    438         p1 = p1->__next_;
    439         _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
    440     }
    441     hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_);
    442     __c_node* p2 = __cbeg_[hc];
    443     _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
    444     while (p2->__c_ != c2)
    445     {
    446         p2 = p2->__next_;
    447         _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
    448     }
    449     std::swap(p1->beg_, p2->beg_);
    450     std::swap(p1->end_, p2->end_);
    451     std::swap(p1->cap_, p2->cap_);
    452     for (__i_node** p = p1->beg_; p != p1->end_; ++p)
    453         (*p)->__c_ = p1;
    454     for (__i_node** p = p2->beg_; p != p2->end_; ++p)
    455         (*p)->__c_ = p2;
    456 }
    457 
    458 void
    459 __libcpp_db::__insert_i(void* __i)
    460 {
    461 #ifndef _LIBCPP_HAS_NO_THREADS
    462     WLock _(mut());
    463 #endif
    464     __insert_iterator(__i);
    465 }
    466 
    467 void
    468 __c_node::__add(__i_node* i)
    469 {
    470     if (end_ == cap_)
    471     {
    472         size_t nc = 2*static_cast<size_t>(cap_ - beg_);
    473         if (nc == 0)
    474             nc = 1;
    475         __i_node** beg =
    476            static_cast<__i_node**>(malloc(nc * sizeof(__i_node*)));
    477         if (beg == nullptr)
    478 #ifndef _LIBCPP_NO_EXCEPTIONS
    479             throw bad_alloc();
    480 #else
    481             abort();
    482 #endif
    483         if (nc > 1)
    484             memcpy(beg, beg_, nc/2*sizeof(__i_node*));
    485         free(beg_);
    486         beg_ = beg;
    487         end_ = beg_ + nc/2;
    488         cap_ = beg_ + nc;
    489     }
    490     *end_++ = i;
    491 }
    492 
    493 // private api
    494 
    495 _LIBCPP_HIDDEN
    496 __i_node*
    497 __libcpp_db::__insert_iterator(void* __i)
    498 {
    499     if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
    500     {
    501         size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
    502         __i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(void*)));
    503         if (ibeg == nullptr)
    504 #ifndef _LIBCPP_NO_EXCEPTIONS
    505             throw bad_alloc();
    506 #else
    507             abort();
    508 #endif
    509         for (__i_node** p = __ibeg_; p != __iend_; ++p)
    510         {
    511             __i_node* q = *p;
    512             while (q != nullptr)
    513             {
    514                 size_t h = hash<void*>()(q->__i_) % nc;
    515                 __i_node* r = q->__next_;
    516                 q->__next_ = ibeg[h];
    517                 ibeg[h] = q;
    518                 q = r;
    519             }
    520         }
    521         free(__ibeg_);
    522         __ibeg_ = ibeg;
    523         __iend_ = __ibeg_ + nc;
    524     }
    525     size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
    526     __i_node* p = __ibeg_[hi];
    527     __i_node* r = __ibeg_[hi] =
    528       static_cast<__i_node*>(malloc(sizeof(__i_node)));
    529     if (r == nullptr)
    530 #ifndef _LIBCPP_NO_EXCEPTIONS
    531         throw bad_alloc();
    532 #else
    533         abort();
    534 #endif
    535     ::new(r) __i_node(__i, p, nullptr);
    536     ++__isz_;
    537     return r;
    538 }
    539 
    540 _LIBCPP_HIDDEN
    541 __i_node*
    542 __libcpp_db::__find_iterator(const void* __i) const
    543 {
    544     __i_node* r = nullptr;
    545     if (__ibeg_ != __iend_)
    546     {
    547         size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
    548         for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
    549         {
    550             if (nd->__i_ == __i)
    551             {
    552                 r = nd;
    553                 break;
    554             }
    555         }
    556     }
    557     return r;
    558 }
    559 
    560 _LIBCPP_HIDDEN
    561 void
    562 __c_node::__remove(__i_node* p)
    563 {
    564     __i_node** r = find(beg_, end_, p);
    565     _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
    566     if (--end_ != r)
    567         memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*));
    568 }
    569 
    570 _LIBCPP_END_NAMESPACE_STD
    571