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