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