]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libc++/src/debug.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / libc++ / src / debug.cpp
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(__unix__) &&  defined(__ELF__) && defined(_LIBCPP_HAS_COMMENT_LIB_PRAGMA)
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 != nullptr && 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