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 != 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 |
579 | |