From db1b7310d7021700b5a7bcea1989b2a625529f40 Mon Sep 17 00:00:00 2001 From: Yasushi Saito Date: Tue, 13 Apr 2021 19:59:46 -0700 Subject: Call FailureSignalHandlerOptions.writenfn with nullptr at the end (#938) * Call FailureSignalHandlerOptions.writenfn with nullptr at the end This behavior has already been alluded to in the document, but it hasn't been implemented. This PR calls changes the failure signal handler to call writerfn(nullptr) at the end of the message block. It also clarifies the documentation. https://github.com/abseil/abseil-cpp/issues/933 * Update failure_signal_handler.h Co-authored-by: Derek Mauro <761129+derekmauro@users.noreply.github.com> --- absl/debugging/failure_signal_handler.cc | 1 + absl/debugging/failure_signal_handler.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'absl/debugging') diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index a9ed6ef9..e458a795 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -366,6 +366,7 @@ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) { // goes after this point. if (fsh_options.writerfn != nullptr) { WriteFailureInfo(signo, ucontext, my_cpu, fsh_options.writerfn); + fsh_options.writerfn(nullptr); } if (fsh_options.call_previous_handler) { diff --git a/absl/debugging/failure_signal_handler.h b/absl/debugging/failure_signal_handler.h index 0c0f585d..500115c0 100644 --- a/absl/debugging/failure_signal_handler.h +++ b/absl/debugging/failure_signal_handler.h @@ -90,7 +90,7 @@ struct FailureSignalHandlerOptions { // If non-null, indicates a pointer to a callback function that will be called // upon failure, with a string argument containing failure data. This function // may be used as a hook to write failure data to a secondary location, such - // as a log file. This function may also be called with null data, as a hint + // as a log file. This function will also be called with null data, as a hint // to flush any buffered data before the program may be terminated. Consider // flushing any buffered data in all calls to this function. // -- cgit v1.2.3 From 1ae9b71c474628d60eb251a3f62967fe64151bb2 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 20 Apr 2021 07:17:48 -0700 Subject: Export of internal Abseil changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -- ac1df60490c9583e475e22de7adfc40023196fbf by Martijn Vels : Change Cord constructor(string_view) to explicit make_tree and Cordz tracking This CL changes the ctor to use an easier to maintain model where Cord code explicitly invokes Cordz update or new / tree logic, which avoids the ambiguity of the 'branched' InlineRep::set_tree code. This removes the need to equip InlineRep with 'MethodIdentifier' or other necessary call info, and also is a cleaner model: InlineRep is carrying too much code now that should plainly sit in Cord, especially with all internal abstractions having moved to InlineData. See child CL(s) for desired state PiperOrigin-RevId: 369433619 -- b665af7f586e6c679a8b27d4f78d5a1d2b596058 by Abseil Team : Rename the 'Compare' template type to 'LessThan', as the passed-in function is expected to act like operator<. It is worth avoiding confusion with std::compare, which returns an int (-1/0/1), as due to implicit casting this can lead to hard-to-spot bugs. PiperOrigin-RevId: 369391118 -- c3c775269cad0f4982ec63f3616dd78bb9e52dca by Martijn Vels : Integrate CordzUpdateTracker into CordzInfo PiperOrigin-RevId: 369348824 -- 771d81ed357496c117179e1daec76eba5155932d by Martijn Vels : Replace mutex() with Lock() / Unlock() function Mini design future tracking of CordzInfo sampled cords: CordzInfo holds a CordRep* reference without a reference count. Cord is responsible for synchronizing updates for sampled cords such that the CordRep* contained in CordzInfo is at all times valid. This is done by scoping Lock() and Unlock() calls around the code modifying the code of a sampled cord. For example (using the future CL CordzUpdateScope()): CordzInfo* cordz_info = get_cordz_info(); CordzUpdateScope scope(cordz_info, CordzUpdateTracker::kRemovePrefix); CordRep* rep = RemovePrefixImpl(root); set_tree(rep); if (cordz_info) { cordz_info->SetCordRep(rep); } On CordzInfo::Unlock(), if the internal rep is null, the cord is no longer sampled, and CordzInfo will be deleted. Thus any update resulting in the Cord being inlined will automatically no longer be sampled. PiperOrigin-RevId: 369338802 -- 5563c12df04a1e965a03b50bdd032739c55c0706 by Martijn Vels : Add UpdateTracker to CordzStatistics PiperOrigin-RevId: 369318178 -- 6b4d8463722a3e55a3e8f6cb3741a41055e7f83e by Martijn Vels : Add kClear, kConstructor* and kUnknown values and fix typo PiperOrigin-RevId: 369297163 -- 041adcbc929789d6d53371a8236840fc350e1eeb by Derek Mauro : Switch from malloc to operator new in pool_urbg.cc so it can only fail by throwing/aborting PiperOrigin-RevId: 369274087 -- 5d97a5f43e3f2d02d0a5bbe586d93b5751812981 by Benjamin Barenblat : Correct Thumb function bound computation in the symbolizer On 32-bit ARM, all functions are aligned to multiples of two bytes, and the lowest-order bit in a function’s address is ignored by the CPU when computing branch targets. That bit is still present in instructions and ELF symbol tables, though; it’s repurposed to indicate whether the function contains ARM or Thumb code. If the symbolizer doesn’t ignore that bit, it will believe Thumb functions have boundaries that are off by one byte, so instruct the symbolizer to null out the lowest-order bit after retrieving it from the symbol table. PiperOrigin-RevId: 369254082 -- 462bb307c6cc332c1e2c3adb5f0cad51804bf937 by Derek Mauro : Add a check for malloc failure in pool_urbg.cc GitHub #940 PiperOrigin-RevId: 369238100 GitOrigin-RevId: ac1df60490c9583e475e22de7adfc40023196fbf Change-Id: Ic6ec91c62cd3a0031f6a75a43a83da959ece2d25 --- absl/algorithm/container.h | 180 ++++++++++----------- absl/debugging/symbolize_elf.inc | 10 ++ absl/debugging/symbolize_test.cc | 43 +++++ absl/random/internal/pool_urbg.cc | 7 +- absl/strings/BUILD.bazel | 4 + absl/strings/CMakeLists.txt | 4 + absl/strings/cord.cc | 6 +- absl/strings/cord.h | 3 + absl/strings/internal/cordz_info.cc | 78 +++++++-- absl/strings/internal/cordz_info.h | 67 +++++--- absl/strings/internal/cordz_info_test.cc | 76 +++++++-- absl/strings/internal/cordz_statistics.h | 12 ++ absl/strings/internal/cordz_update_tracker.h | 22 +-- absl/strings/internal/cordz_update_tracker_test.cc | 25 ++- 14 files changed, 382 insertions(+), 155 deletions(-) (limited to 'absl/debugging') diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h index 6398438f..1652e7b0 100644 --- a/absl/algorithm/container.h +++ b/absl/algorithm/container.h @@ -905,11 +905,11 @@ void c_sort(C& c) { // Overload of c_sort() for performing a `comp` comparison other than the // default `operator<`. -template -void c_sort(C& c, Compare&& comp) { +template +void c_sort(C& c, LessThan&& comp) { std::sort(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_stable_sort() @@ -925,11 +925,11 @@ void c_stable_sort(C& c) { // Overload of c_stable_sort() for performing a `comp` comparison other than the // default `operator<`. -template -void c_stable_sort(C& c, Compare&& comp) { +template +void c_stable_sort(C& c, LessThan&& comp) { std::stable_sort(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_is_sorted() @@ -944,11 +944,11 @@ bool c_is_sorted(const C& c) { // c_is_sorted() overload for performing a `comp` comparison other than the // default `operator<`. -template -bool c_is_sorted(const C& c, Compare&& comp) { +template +bool c_is_sorted(const C& c, LessThan&& comp) { return std::is_sorted(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_partial_sort() @@ -966,14 +966,14 @@ void c_partial_sort( // Overload of c_partial_sort() for performing a `comp` comparison other than // the default `operator<`. -template +template void c_partial_sort( RandomAccessContainer& sequence, container_algorithm_internal::ContainerIter middle, - Compare&& comp) { + LessThan&& comp) { std::partial_sort(container_algorithm_internal::c_begin(sequence), middle, container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_partial_sort_copy() @@ -994,15 +994,15 @@ c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) { // Overload of c_partial_sort_copy() for performing a `comp` comparison other // than the default `operator<`. -template +template container_algorithm_internal::ContainerIter c_partial_sort_copy(const C& sequence, RandomAccessContainer& result, - Compare&& comp) { + LessThan&& comp) { return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_begin(result), container_algorithm_internal::c_end(result), - std::forward(comp)); + std::forward(comp)); } // c_is_sorted_until() @@ -1018,12 +1018,12 @@ container_algorithm_internal::ContainerIter c_is_sorted_until(C& c) { // Overload of c_is_sorted_until() for performing a `comp` comparison other than // the default `operator<`. -template +template container_algorithm_internal::ContainerIter c_is_sorted_until( - C& c, Compare&& comp) { + C& c, LessThan&& comp) { return std::is_sorted_until(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_nth_element() @@ -1043,14 +1043,14 @@ void c_nth_element( // Overload of c_nth_element() for performing a `comp` comparison other than // the default `operator<`. -template +template void c_nth_element( RandomAccessContainer& sequence, container_algorithm_internal::ContainerIter nth, - Compare&& comp) { + LessThan&& comp) { std::nth_element(container_algorithm_internal::c_begin(sequence), nth, container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1072,12 +1072,12 @@ container_algorithm_internal::ContainerIter c_lower_bound( // Overload of c_lower_bound() for performing a `comp` comparison other than // the default `operator<`. -template +template container_algorithm_internal::ContainerIter c_lower_bound( - Sequence& sequence, T&& value, Compare&& comp) { + Sequence& sequence, T&& value, LessThan&& comp) { return std::lower_bound(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(value), std::forward(comp)); + std::forward(value), std::forward(comp)); } // c_upper_bound() @@ -1095,12 +1095,12 @@ container_algorithm_internal::ContainerIter c_upper_bound( // Overload of c_upper_bound() for performing a `comp` comparison other than // the default `operator<`. -template +template container_algorithm_internal::ContainerIter c_upper_bound( - Sequence& sequence, T&& value, Compare&& comp) { + Sequence& sequence, T&& value, LessThan&& comp) { return std::upper_bound(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(value), std::forward(comp)); + std::forward(value), std::forward(comp)); } // c_equal_range() @@ -1118,12 +1118,12 @@ c_equal_range(Sequence& sequence, T&& value) { // Overload of c_equal_range() for performing a `comp` comparison other than // the default `operator<`. -template +template container_algorithm_internal::ContainerIterPairType -c_equal_range(Sequence& sequence, T&& value, Compare&& comp) { +c_equal_range(Sequence& sequence, T&& value, LessThan&& comp) { return std::equal_range(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(value), std::forward(comp)); + std::forward(value), std::forward(comp)); } // c_binary_search() @@ -1140,12 +1140,12 @@ bool c_binary_search(Sequence&& sequence, T&& value) { // Overload of c_binary_search() for performing a `comp` comparison other than // the default `operator<`. -template -bool c_binary_search(Sequence&& sequence, T&& value, Compare&& comp) { +template +bool c_binary_search(Sequence&& sequence, T&& value, LessThan&& comp) { return std::binary_search(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), std::forward(value), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1166,14 +1166,14 @@ OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result) { // Overload of c_merge() for performing a `comp` comparison other than // the default `operator<`. -template +template OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result, - Compare&& comp) { + LessThan&& comp) { return std::merge(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), result, - std::forward(comp)); + std::forward(comp)); } // c_inplace_merge() @@ -1189,13 +1189,13 @@ void c_inplace_merge(C& c, // Overload of c_inplace_merge() for performing a merge using a `comp` other // than `operator<`. -template +template void c_inplace_merge(C& c, container_algorithm_internal::ContainerIter middle, - Compare&& comp) { + LessThan&& comp) { std::inplace_merge(container_algorithm_internal::c_begin(c), middle, container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_includes() @@ -1213,13 +1213,13 @@ bool c_includes(const C1& c1, const C2& c2) { // Overload of c_includes() for performing a merge using a `comp` other than // `operator<`. -template -bool c_includes(const C1& c1, const C2& c2, Compare&& comp) { +template +bool c_includes(const C1& c1, const C2& c2, LessThan&& comp) { return std::includes(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), - std::forward(comp)); + std::forward(comp)); } // c_set_union() @@ -1243,7 +1243,7 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) { // Overload of c_set_union() for performing a merge using a `comp` other than // `operator<`. -template ::value, void>::type, @@ -1251,12 +1251,12 @@ template ::value, void>::type> OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output, - Compare&& comp) { + LessThan&& comp) { return std::set_union(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), output, - std::forward(comp)); + std::forward(comp)); } // c_set_intersection() @@ -1280,7 +1280,7 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2, // Overload of c_set_intersection() for performing a merge using a `comp` other // than `operator<`. -template ::value, void>::type, @@ -1288,12 +1288,12 @@ template ::value, void>::type> OutputIterator c_set_intersection(const C1& c1, const C2& c2, - OutputIterator output, Compare&& comp) { + OutputIterator output, LessThan&& comp) { return std::set_intersection(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), output, - std::forward(comp)); + std::forward(comp)); } // c_set_difference() @@ -1318,7 +1318,7 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2, // Overload of c_set_difference() for performing a merge using a `comp` other // than `operator<`. -template ::value, void>::type, @@ -1326,12 +1326,12 @@ template ::value, void>::type> OutputIterator c_set_difference(const C1& c1, const C2& c2, - OutputIterator output, Compare&& comp) { + OutputIterator output, LessThan&& comp) { return std::set_difference(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), output, - std::forward(comp)); + std::forward(comp)); } // c_set_symmetric_difference() @@ -1357,7 +1357,7 @@ OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, // Overload of c_set_symmetric_difference() for performing a merge using a // `comp` other than `operator<`. -template ::value, void>::type, @@ -1366,13 +1366,13 @@ template ::type> OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, OutputIterator output, - Compare&& comp) { + LessThan&& comp) { return std::set_symmetric_difference( container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), output, - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1391,11 +1391,11 @@ void c_push_heap(RandomAccessContainer& sequence) { // Overload of c_push_heap() for performing a push operation on a heap using a // `comp` other than `operator<`. -template -void c_push_heap(RandomAccessContainer& sequence, Compare&& comp) { +template +void c_push_heap(RandomAccessContainer& sequence, LessThan&& comp) { std::push_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_pop_heap() @@ -1410,11 +1410,11 @@ void c_pop_heap(RandomAccessContainer& sequence) { // Overload of c_pop_heap() for performing a pop operation on a heap using a // `comp` other than `operator<`. -template -void c_pop_heap(RandomAccessContainer& sequence, Compare&& comp) { +template +void c_pop_heap(RandomAccessContainer& sequence, LessThan&& comp) { std::pop_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_make_heap() @@ -1429,11 +1429,11 @@ void c_make_heap(RandomAccessContainer& sequence) { // Overload of c_make_heap() for performing heap comparisons using a // `comp` other than `operator<` -template -void c_make_heap(RandomAccessContainer& sequence, Compare&& comp) { +template +void c_make_heap(RandomAccessContainer& sequence, LessThan&& comp) { std::make_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_sort_heap() @@ -1448,11 +1448,11 @@ void c_sort_heap(RandomAccessContainer& sequence) { // Overload of c_sort_heap() for performing heap comparisons using a // `comp` other than `operator<` -template -void c_sort_heap(RandomAccessContainer& sequence, Compare&& comp) { +template +void c_sort_heap(RandomAccessContainer& sequence, LessThan&& comp) { std::sort_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_is_heap() @@ -1467,11 +1467,11 @@ bool c_is_heap(const RandomAccessContainer& sequence) { // Overload of c_is_heap() for performing heap comparisons using a // `comp` other than `operator<` -template -bool c_is_heap(const RandomAccessContainer& sequence, Compare&& comp) { +template +bool c_is_heap(const RandomAccessContainer& sequence, LessThan&& comp) { return std::is_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_is_heap_until() @@ -1487,12 +1487,12 @@ c_is_heap_until(RandomAccessContainer& sequence) { // Overload of c_is_heap_until() for performing heap comparisons using a // `comp` other than `operator<` -template +template container_algorithm_internal::ContainerIter -c_is_heap_until(RandomAccessContainer& sequence, Compare&& comp) { +c_is_heap_until(RandomAccessContainer& sequence, LessThan&& comp) { return std::is_heap_until(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1513,12 +1513,12 @@ container_algorithm_internal::ContainerIter c_min_element( // Overload of c_min_element() for performing a `comp` comparison other than // `operator<`. -template +template container_algorithm_internal::ContainerIter c_min_element( - Sequence& sequence, Compare&& comp) { + Sequence& sequence, LessThan&& comp) { return std::min_element(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_max_element() @@ -1535,12 +1535,12 @@ container_algorithm_internal::ContainerIter c_max_element( // Overload of c_max_element() for performing a `comp` comparison other than // `operator<`. -template +template container_algorithm_internal::ContainerIter c_max_element( - Sequence& sequence, Compare&& comp) { + Sequence& sequence, LessThan&& comp) { return std::max_element(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_minmax_element() @@ -1558,12 +1558,12 @@ c_minmax_element(C& c) { // Overload of c_minmax_element() for performing `comp` comparisons other than // `operator<`. -template +template container_algorithm_internal::ContainerIterPairType -c_minmax_element(C& c, Compare&& comp) { +c_minmax_element(C& c, LessThan&& comp) { return std::minmax_element(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1588,15 +1588,15 @@ bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2) { // Overload of c_lexicographical_compare() for performing a lexicographical // comparison using a `comp` operator instead of `operator<`. -template +template bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2, - Compare&& comp) { + LessThan&& comp) { return std::lexicographical_compare( container_algorithm_internal::c_begin(sequence1), container_algorithm_internal::c_end(sequence1), container_algorithm_internal::c_begin(sequence2), container_algorithm_internal::c_end(sequence2), - std::forward(comp)); + std::forward(comp)); } // c_next_permutation() @@ -1612,11 +1612,11 @@ bool c_next_permutation(C& c) { // Overload of c_next_permutation() for performing a lexicographical // comparison using a `comp` operator instead of `operator<`. -template -bool c_next_permutation(C& c, Compare&& comp) { +template +bool c_next_permutation(C& c, LessThan&& comp) { return std::next_permutation(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_prev_permutation() @@ -1632,11 +1632,11 @@ bool c_prev_permutation(C& c) { // Overload of c_prev_permutation() for performing a lexicographical // comparison using a `comp` operator instead of `operator<`. -template -bool c_prev_permutation(C& c, Compare&& comp) { +template +bool c_prev_permutation(C& c, LessThan&& comp) { return std::prev_permutation(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index f4d5727b..87dbd078 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc @@ -701,6 +701,16 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( const char *start_address = ComputeOffset(original_start_address, relocation); +#ifdef __arm__ + // ARM functions are always aligned to multiples of two bytes; the + // lowest-order bit in start_address is ignored by the CPU and indicates + // whether the function contains ARM (0) or Thumb (1) code. We don't care + // about what encoding is being used; we just want the real start address + // of the function. + start_address = reinterpret_cast( + reinterpret_cast(start_address) & ~1); +#endif + if (deref_function_descriptor_pointer && InSection(original_start_address, opd)) { // The opd section is mapped into memory. Just dereference diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index a2dd4956..35de02e2 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -477,6 +477,46 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { #endif } +#if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) +// Test that we correctly identify bounds of Thumb functions on ARM. +// +// Thumb functions have the lowest-order bit set in their addresses in the ELF +// symbol table. This requires some extra logic to properly compute function +// bounds. To test this logic, nudge a Thumb function right up against an ARM +// function and try to symbolize the ARM function. +// +// A naive implementation will simply use the Thumb function's entry point as +// written in the symbol table and will therefore treat the Thumb function as +// extending one byte further in the instruction stream than it actually does. +// When asked to symbolize the start of the ARM function, it will identify an +// overlap between the Thumb and ARM functions, and it will return the name of +// the Thumb function. +// +// A correct implementation, on the other hand, will null out the lowest-order +// bit in the Thumb function's entry point. It will correctly compute the end of +// the Thumb function, it will find no overlap between the Thumb and ARM +// functions, and it will return the name of the ARM function. + +__attribute__((target("thumb"))) int ArmThumbOverlapThumb(int x) { + return x * x * x; +} + +__attribute__((target("arm"))) int ArmThumbOverlapArm(int x) { + return x * x * x; +} + +void ABSL_ATTRIBUTE_NOINLINE TestArmThumbOverlap() { +#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) + const char *symbol = TrySymbolize((void *)&ArmThumbOverlapArm); + ABSL_RAW_CHECK(symbol != nullptr, "TestArmThumbOverlap failed"); + ABSL_RAW_CHECK(strcmp("ArmThumbOverlapArm()", symbol) == 0, + "TestArmThumbOverlap failed"); + std::cout << "TestArmThumbOverlap passed" << std::endl; +#endif +} + +#endif // defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) + #elif defined(_WIN32) #if !defined(ABSL_CONSUME_DLL) @@ -551,6 +591,9 @@ int main(int argc, char **argv) { TestWithPCInsideInlineFunction(); TestWithPCInsideNonInlineFunction(); TestWithReturnAddress(); +#if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) + TestArmThumbOverlap(); +#endif #endif return RUN_ALL_TESTS(); diff --git a/absl/random/internal/pool_urbg.cc b/absl/random/internal/pool_urbg.cc index 5bee5307..725100a4 100644 --- a/absl/random/internal/pool_urbg.cc +++ b/absl/random/internal/pool_urbg.cc @@ -194,11 +194,10 @@ RandenPoolEntry* PoolAlignedAlloc() { // Not all the platforms that we build for have std::aligned_alloc, however // since we never free these objects, we can over allocate and munge the // pointers to the correct alignment. - void* memory = std::malloc(sizeof(RandenPoolEntry) + kAlignment); - auto x = reinterpret_cast(memory); + intptr_t x = reinterpret_cast( + new char[sizeof(RandenPoolEntry) + kAlignment]); auto y = x % kAlignment; - void* aligned = - (y == 0) ? memory : reinterpret_cast(x + kAlignment - y); + void* aligned = reinterpret_cast(y == 0 ? x : (x + kAlignment - y)); return new (aligned) RandenPoolEntry(); } diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 1306ea65..95ed0868 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -368,6 +368,7 @@ cc_library( ":cord_internal", ":cordz_handle", ":cordz_statistics", + ":cordz_update_tracker", "//absl/base:config", "//absl/base:core_headers", "//absl/debugging:stacktrace", @@ -406,6 +407,7 @@ cc_library( hdrs = ["internal/cordz_statistics.h"], copts = ABSL_DEFAULT_COPTS, deps = [ + ":cordz_update_tracker", "//absl/base:config", ], ) @@ -450,6 +452,8 @@ cc_test( ":cord_internal", ":cordz_handle", ":cordz_info", + ":cordz_statistics", + ":cordz_update_tracker", ":strings", "//absl/base:config", "//absl/debugging:stacktrace", diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 8f41f064..5a13831f 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -641,6 +641,7 @@ absl_cc_library( DEPS absl::config absl::core_headers + absl::cordz_update_tracker absl::synchronization ) @@ -690,6 +691,7 @@ absl_cc_library( absl::cord_internal absl::cordz_handle absl::cordz_statistics + absl::cordz_update_tracker absl::core_headers absl::span absl::stacktrace @@ -707,6 +709,8 @@ absl_cc_test( absl::cord_test_helpers absl::cordz_handle absl::cordz_info + absl::cordz_statistics + absl::cordz_update_tracker absl::span absl::stacktrace absl::symbolize diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index d33d6a0d..770c5a70 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -39,6 +39,7 @@ #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cord_rep_ring.h" #include "absl/strings/internal/cordz_statistics.h" +#include "absl/strings/internal/cordz_update_tracker.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" @@ -544,7 +545,10 @@ Cord::Cord(absl::string_view src) { if (n <= InlineRep::kMaxInline) { contents_.set_data(src.data(), n, false); } else { - contents_.set_tree(NewTree(src.data(), n, 0)); + contents_.data_.make_tree(NewTree(src.data(), n, 0)); + if (ABSL_PREDICT_FALSE(absl::cord_internal::cordz_should_profile())) { + contents_.StartProfiling(); + } } } diff --git a/absl/strings/cord.h b/absl/strings/cord.h index de1470b2..1e6a73a5 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -84,6 +84,7 @@ #include "absl/strings/internal/cordz_functions.h" #include "absl/strings/internal/cordz_info.h" #include "absl/strings/internal/cordz_statistics.h" +#include "absl/strings/internal/cordz_update_tracker.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/string_constant.h" #include "absl/strings/string_view.h" @@ -668,6 +669,8 @@ class Cord { explicit constexpr Cord(strings_internal::StringConstant); private: + using CordzUpdateTracker = cord_internal::CordzUpdateTracker; + friend class CordTestPeer; friend bool operator==(const Cord& lhs, const Cord& rhs); friend bool operator==(const Cord& lhs, absl::string_view rhs); diff --git a/absl/strings/internal/cordz_info.cc b/absl/strings/internal/cordz_info.cc index 4dec63d5..6540d134 100644 --- a/absl/strings/internal/cordz_info.cc +++ b/absl/strings/internal/cordz_info.cc @@ -19,6 +19,7 @@ #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cordz_handle.h" #include "absl/strings/internal/cordz_statistics.h" +#include "absl/strings/internal/cordz_update_tracker.h" #include "absl/synchronization/mutex.h" #include "absl/types/span.h" @@ -44,18 +45,15 @@ CordzInfo* CordzInfo::Next(const CordzSnapshot& snapshot) const { return ci_next_unsafe(); } -CordzInfo* CordzInfo::TrackCord(CordRep* rep, const CordzInfo* src) { - CordzInfo* ci = new CordzInfo(rep); - if (src) { - ci->parent_stack_depth_ = src->stack_depth_; - memcpy(ci->parent_stack_, src->stack_, sizeof(void*) * src->stack_depth_); - } +CordzInfo* CordzInfo::TrackCord(CordRep* rep, const CordzInfo* src, + MethodIdentifier method) { + CordzInfo* ci = new CordzInfo(rep, src, method); ci->Track(); return ci; } -CordzInfo* CordzInfo::TrackCord(CordRep* rep) { - return TrackCord(rep, nullptr); +CordzInfo* CordzInfo::TrackCord(CordRep* rep, MethodIdentifier method) { + return TrackCord(rep, nullptr, method); } void CordzInfo::UntrackCord(CordzInfo* cordz_info) { @@ -66,12 +64,35 @@ void CordzInfo::UntrackCord(CordzInfo* cordz_info) { } } -CordzInfo::CordzInfo(CordRep* rep) +CordzInfo::MethodIdentifier CordzInfo::GetParentMethod(const CordzInfo* src) { + if (src == nullptr) return MethodIdentifier::kUnknown; + return src->parent_method_ != MethodIdentifier::kUnknown ? src->parent_method_ + : src->method_; +} + +int CordzInfo::FillParentStack(const CordzInfo* src, void** stack) { + assert(stack); + if (src == nullptr) return 0; + if (src->parent_stack_depth_) { + memcpy(stack, src->parent_stack_, src->parent_stack_depth_ * sizeof(void*)); + return src->parent_stack_depth_; + } + memcpy(stack, src->stack_, src->stack_depth_ * sizeof(void*)); + return src->stack_depth_; +} + +CordzInfo::CordzInfo(CordRep* rep, const CordzInfo* src, + MethodIdentifier method) : rep_(rep), stack_depth_(absl::GetStackTrace(stack_, /*max_depth=*/kMaxStackDepth, /*skip_count=*/1)), - parent_stack_depth_(0), - create_time_(absl::Now()) {} + parent_stack_depth_(FillParentStack(src, parent_stack_)), + method_(method), + parent_method_(GetParentMethod(src)), + create_time_(absl::Now()), + size_(rep->length) { + update_tracker_.LossyAdd(method); +} CordzInfo::~CordzInfo() { // `rep_` is potentially kept alive if CordzInfo is included @@ -96,7 +117,7 @@ void CordzInfo::Untrack() { { // TODO(b/117940323): change this to assuming ownership instead once all // Cord logic is properly keeping `rep_` in sync with the Cord root rep. - absl::MutexLock lock(&mutex()); + absl::MutexLock lock(&mutex_); rep_ = nullptr; } @@ -120,9 +141,31 @@ void CordzInfo::Untrack() { } } +void CordzInfo::Lock(MethodIdentifier method) + ABSL_EXCLUSIVE_LOCK_FUNCTION(mutex_) { + mutex_.Lock(); + update_tracker_.LossyAdd(method); + assert(rep_); +} + +void CordzInfo::Unlock() ABSL_UNLOCK_FUNCTION(mutex_) { + bool tracked = rep_ != nullptr; + if (rep_) { + size_.store(rep_->length); + } + mutex_.Unlock(); + if (!tracked) { + Untrack(); + CordzHandle::Delete(this); + } +} + void CordzInfo::SetCordRep(CordRep* rep) { - mutex().AssertHeld(); + mutex_.AssertHeld(); rep_ = rep; + if (rep) { + size_.store(rep->length); + } } absl::Span CordzInfo::GetStack() const { @@ -133,6 +176,15 @@ absl::Span CordzInfo::GetParentStack() const { return absl::MakeConstSpan(parent_stack_, parent_stack_depth_); } +CordzStatistics CordzInfo::GetCordzStatistics() const { + CordzStatistics stats; + stats.method = method_; + stats.parent_method = parent_method_; + stats.update_tracker = update_tracker_; + stats.size = size_.load(std::memory_order_relaxed); + return stats; +} + } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/strings/internal/cordz_info.h b/absl/strings/internal/cordz_info.h index c1090a1c..5345be75 100644 --- a/absl/strings/internal/cordz_info.h +++ b/absl/strings/internal/cordz_info.h @@ -24,6 +24,7 @@ #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cordz_handle.h" #include "absl/strings/internal/cordz_statistics.h" +#include "absl/strings/internal/cordz_update_tracker.h" #include "absl/synchronization/mutex.h" #include "absl/types/span.h" @@ -42,13 +43,20 @@ namespace cord_internal { // the destructor of a CordzSampleToken object. class CordzInfo : public CordzHandle { public: + using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; + // All profiled Cords should be accompanied by a call to TrackCord. // TrackCord creates a CordzInfo instance which tracks important metrics of // the sampled cord. CordzInfo instances are placed in a global list which is // used to discover and snapshot all actively tracked cords. // Callers are responsible for calling UntrackCord() before the tracked Cord // instance is deleted, or to stop tracking the sampled Cord. - static CordzInfo* TrackCord(CordRep* rep); + // Callers are also responsible for guarding changes to `rep` through the + // Lock() and Unlock() calls, and calling SetCordRep() if the root of the + // sampled cord changes before the old root has been unreffed and/or deleted. + // `method` identifies the Cord method which initiated the cord to be sampled. + static CordzInfo* TrackCord( + CordRep* rep, MethodIdentifier method = MethodIdentifier::kUnknown); // Stops tracking changes for a sampled cord, and deletes the provided info. // This function must be called before the sampled cord instance is deleted, @@ -58,10 +66,12 @@ class CordzInfo : public CordzHandle { static void UntrackCord(CordzInfo* cordz_info); // Identical to TrackCord(), except that this function fills the - // 'parent_stack' property of the returned CordzInfo instance from the - // provided `src` instance if `src` is not null. + // `parent_stack` and `parent_method` properties of the returned CordzInfo + // instance from the provided `src` instance if `src` is not null. // This function should be used for sampling 'copy constructed' cords. - static CordzInfo* TrackCord(CordRep* rep, const CordzInfo* src); + static CordzInfo* TrackCord( + CordRep* rep, const CordzInfo* src, + MethodIdentifier method = MethodIdentifier::kUnknown); CordzInfo() = delete; CordzInfo(const CordzInfo&) = delete; @@ -73,17 +83,20 @@ class CordzInfo : public CordzHandle { // Retrieves the next oldest existing CordzInfo older than 'this' instance. CordzInfo* Next(const CordzSnapshot& snapshot) const; - // Returns a reference to the mutex guarding the `rep` property of this - // instance. CordzInfo instances hold a weak reference to the rep pointer of - // sampled cords, and rely on Cord logic to update the rep pointer when the - // underlying root tree or ring of the cord changes. - absl::Mutex& mutex() const { return mutex_; } + // Locks this instance for the update identified by `method`. + // Increases the count for `method` in `update_tracker`. + void Lock(MethodIdentifier method) ABSL_EXCLUSIVE_LOCK_FUNCTION(mutex_); + + // Unlocks this instance. If the contained `rep` has been set to null + // indicating the Cord has been cleared or is otherwise no longer sampled, + // then this method will delete this CordzInfo instance. + void Unlock() ABSL_UNLOCK_FUNCTION(mutex_); // Updates the `rep' property of this instance. This methods is invoked by // Cord logic each time the root node of a sampled Cord changes, and before // the old root reference count is deleted. This guarantees that collection // code can always safely take a reference on the tracked cord. - // Requires `mutex()` to be held. + // Requires a lock to be held through the `Lock()` method. // TODO(b/117940323): annotate with ABSL_EXCLUSIVE_LOCKS_REQUIRED once all // Cord code is in a state where this can be proven true by the compiler. void SetCordRep(CordRep* rep); @@ -106,15 +119,10 @@ class CordzInfo : public CordzHandle { // from, or being assigned the value of an existing (sampled) cord. absl::Span GetParentStack() const; - // Retrieve the CordzStatistics associated with this Cord. The statistics are - // only updated when a Cord goes through a mutation, such as an Append or - // RemovePrefix. The refcounts can change due to external events, so the - // reported refcount stats might be incorrect. - CordzStatistics GetCordzStatistics() const { - CordzStatistics stats; - stats.size = size_.load(std::memory_order_relaxed); - return stats; - } + // Retrieves the CordzStatistics associated with this Cord. The statistics + // are only updated when a Cord goes through a mutation, such as an Append + // or RemovePrefix. + CordzStatistics GetCordzStatistics() const; // Records size metric for this CordzInfo instance. void RecordMetrics(int64_t size) { @@ -124,9 +132,21 @@ class CordzInfo : public CordzHandle { private: static constexpr int kMaxStackDepth = 64; - explicit CordzInfo(CordRep* tree); + explicit CordzInfo(CordRep* rep, const CordzInfo* src, + MethodIdentifier method); ~CordzInfo() override; + // Returns the parent method from `src`, which is either `parent_method_` or + // `method_` depending on `parent_method_` being kUnknown. + // Returns kUnknown if `src` is null. + static MethodIdentifier GetParentMethod(const CordzInfo* src); + + // Fills the provided stack from `src`, copying either `parent_stack_` or + // `stack_` depending on `parent_stack_` being empty, returning the size of + // the parent stack. + // Returns 0 if `src` is null. + static int FillParentStack(const CordzInfo* src, void** stack); + void Track(); void Untrack(); @@ -149,12 +169,15 @@ class CordzInfo : public CordzHandle { std::atomic ci_next_ ABSL_GUARDED_BY(ci_mutex_){nullptr}; mutable absl::Mutex mutex_; - CordRep* rep_ ABSL_GUARDED_BY(mutex()); + CordRep* rep_ ABSL_GUARDED_BY(mutex_); void* stack_[kMaxStackDepth]; void* parent_stack_[kMaxStackDepth]; const int stack_depth_; - int parent_stack_depth_; + const int parent_stack_depth_; + const MethodIdentifier method_; + const MethodIdentifier parent_method_; + CordzUpdateTracker update_tracker_; const absl::Time create_time_; // Last recorded size for the cord. diff --git a/absl/strings/internal/cordz_info_test.cc b/absl/strings/internal/cordz_info_test.cc index be20e4a4..66acf9b6 100644 --- a/absl/strings/internal/cordz_info_test.cc +++ b/absl/strings/internal/cordz_info_test.cc @@ -23,6 +23,7 @@ #include "absl/debugging/symbolize.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cordz_handle.h" +#include "absl/strings/internal/cordz_update_tracker.h" #include "absl/strings/str_cat.h" #include "absl/types/span.h" @@ -47,6 +48,12 @@ struct TestCordRep { ~TestCordRep() { CordRepFlat::Delete(rep); } }; +// Used test values +auto constexpr kUnknownMethod = CordzUpdateTracker::kUnknown; +auto constexpr kTrackCordMethod = CordzUpdateTracker::kConstructorString; +auto constexpr kChildMethod = CordzUpdateTracker::kConstructorCord; +auto constexpr kUpdateMethod = CordzUpdateTracker::kAppendString; + // Local less verbose helper std::vector DeleteQueue() { return CordzHandle::DiagnosticsGetDeleteQueue(); @@ -90,15 +97,27 @@ TEST(CordzInfoTest, SetCordRep) { CordzInfo* info = CordzInfo::TrackCord(rep.rep); TestCordRep rep2; - { - absl::MutexLock lock(&info->mutex()); - info->SetCordRep(rep2.rep); - } + info->Lock(CordzUpdateTracker::kAppendCord); + info->SetCordRep(rep2.rep); + info->Unlock(); EXPECT_THAT(info->GetCordRepForTesting(), Eq(rep2.rep)); CordzInfo::UntrackCord(info); } +TEST(CordzInfoTest, SetCordRepNullUntracksCordOnUnlock) { + TestCordRep rep; + CordzInfo* info = CordzInfo::TrackCord(rep.rep); + + info->Lock(CordzUpdateTracker::kAppendString); + info->SetCordRep(nullptr); + EXPECT_THAT(info->GetCordRepForTesting(), Eq(nullptr)); + EXPECT_THAT(CordzInfo::Head(CordzSnapshot()), Eq(info)); + + info->Unlock(); + EXPECT_THAT(CordzInfo::Head(CordzSnapshot()), Eq(nullptr)); +} + #if GTEST_HAS_DEATH_TEST TEST(CordzInfoTest, SetCordRepRequiresMutex) { @@ -191,13 +210,41 @@ TEST(CordzInfoTest, StackV2) { // Local helper functions to get different stacks for child and parent. CordzInfo* TrackChildCord(CordRep* rep, const CordzInfo* parent) { - return CordzInfo::TrackCord(rep, parent); + return CordzInfo::TrackCord(rep, parent, kChildMethod); } CordzInfo* TrackParentCord(CordRep* rep) { - return CordzInfo::TrackCord(rep); + return CordzInfo::TrackCord(rep, kTrackCordMethod); } -TEST(CordzInfoTest, ParentStackV2) { +TEST(CordzInfoTest, GetStatistics) { + TestCordRep rep; + CordzInfo* info = TrackParentCord(rep.rep); + + CordzStatistics statistics = info->GetCordzStatistics(); + EXPECT_THAT(statistics.size, Eq(rep.rep->length)); + EXPECT_THAT(statistics.method, Eq(kTrackCordMethod)); + EXPECT_THAT(statistics.parent_method, Eq(kUnknownMethod)); + EXPECT_THAT(statistics.update_tracker.Value(kTrackCordMethod), Eq(1)); + + CordzInfo::UntrackCord(info); +} + +TEST(CordzInfoTest, LockCountsMethod) { + TestCordRep rep; + CordzInfo* info = TrackParentCord(rep.rep); + + info->Lock(kUpdateMethod); + info->Unlock(); + info->Lock(kUpdateMethod); + info->Unlock(); + + CordzStatistics statistics = info->GetCordzStatistics(); + EXPECT_THAT(statistics.update_tracker.Value(kUpdateMethod), Eq(2)); + + CordzInfo::UntrackCord(info); +} + +TEST(CordzInfoTest, FromParent) { TestCordRep rep; CordzInfo* info_parent = TrackParentCord(rep.rep); CordzInfo* info_child = TrackChildCord(rep.rep, info_parent); @@ -206,18 +253,29 @@ TEST(CordzInfoTest, ParentStackV2) { std::string parent_stack = FormatStack(info_child->GetParentStack()); EXPECT_THAT(stack, Eq(parent_stack)); + CordzStatistics statistics = info_child->GetCordzStatistics(); + EXPECT_THAT(statistics.size, Eq(rep.rep->length)); + EXPECT_THAT(statistics.method, Eq(kChildMethod)); + EXPECT_THAT(statistics.parent_method, Eq(kTrackCordMethod)); + EXPECT_THAT(statistics.update_tracker.Value(kChildMethod), Eq(1)); + CordzInfo::UntrackCord(info_parent); CordzInfo::UntrackCord(info_child); } -TEST(CordzInfoTest, ParentStackEmpty) { +TEST(CordzInfoTest, FromParentNullptr) { TestCordRep rep; CordzInfo* info = TrackChildCord(rep.rep, nullptr); EXPECT_TRUE(info->GetParentStack().empty()); + CordzStatistics statistics = info->GetCordzStatistics(); + EXPECT_THAT(statistics.size, Eq(rep.rep->length)); + EXPECT_THAT(statistics.method, Eq(kChildMethod)); + EXPECT_THAT(statistics.parent_method, Eq(kUnknownMethod)); + EXPECT_THAT(statistics.update_tracker.Value(kChildMethod), Eq(1)); CordzInfo::UntrackCord(info); } -TEST(CordzInfoTest, CordzStatisticsV2) { +TEST(CordzInfoTest, RecordMetrics) { TestCordRep rep; CordzInfo* info = TrackParentCord(rep.rep); diff --git a/absl/strings/internal/cordz_statistics.h b/absl/strings/internal/cordz_statistics.h index ce7c39aa..6e335c0b 100644 --- a/absl/strings/internal/cordz_statistics.h +++ b/absl/strings/internal/cordz_statistics.h @@ -18,6 +18,7 @@ #include #include "absl/base/config.h" +#include "absl/strings/internal/cordz_update_tracker.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -25,6 +26,8 @@ namespace cord_internal { // CordzStatistics captures some meta information about a Cord's shape. struct CordzStatistics { + using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; + // The size of the cord in bytes. This matches the result of Cord::size(). int64_t size = 0; @@ -46,6 +49,15 @@ struct CordzStatistics { // For ring buffer Cords, this includes the 'ring buffer' node. // A value of 0 implies the property has not been recorded. int64_t node_count = 0; + + // The cord method responsible for sampling the cord. + MethodIdentifier method = MethodIdentifier::kUnknown; + + // The cord method responsible for sampling the parent cord if applicable. + MethodIdentifier parent_method = MethodIdentifier::kUnknown; + + // Update tracker tracking invocation count per cord method. + CordzUpdateTracker update_tracker; }; } // namespace cord_internal diff --git a/absl/strings/internal/cordz_update_tracker.h b/absl/strings/internal/cordz_update_tracker.h index 3c617e93..a090676d 100644 --- a/absl/strings/internal/cordz_update_tracker.h +++ b/absl/strings/internal/cordz_update_tracker.h @@ -38,20 +38,24 @@ class CordzUpdateTracker { public: // Tracked update methods. enum MethodIdentifier { - kAssignString, - kAssignCord, - kMoveAssignCord, - kAppendString, + kUnknown, kAppendCord, - kMoveAppendCord, - kPrependString, - kPrependCord, - kMovePrependCord, kAppendExternalMemory, + kAppendString, + kAssignCord, + kAssignString, + kClear, + kConstructorCord, + kConstructorString, kFlatten, kGetAppendRegion, + kMoveAppendCord, + kMoveAssignCord, + kMovePrependCord, + kPrependCord, + kPrependString, kRemovePrefix, - kRemoveSuffic, + kRemoveSuffix, kSubCord, // kNumMethods defines the number of entries: must be the last entry. diff --git a/absl/strings/internal/cordz_update_tracker_test.cc b/absl/strings/internal/cordz_update_tracker_test.cc index 45782046..eda662f2 100644 --- a/absl/strings/internal/cordz_update_tracker_test.cc +++ b/absl/strings/internal/cordz_update_tracker_test.cc @@ -36,13 +36,24 @@ using Methods = std::array; // Returns an array of all methods defined in `MethodIdentifier` Methods AllMethods() { - return Methods{Method::kAssignString, Method::kAssignCord, - Method::kMoveAssignCord, Method::kAppendString, - Method::kAppendCord, Method::kMoveAppendCord, - Method::kPrependString, Method::kPrependCord, - Method::kMovePrependCord, Method::kAppendExternalMemory, - Method::kFlatten, Method::kGetAppendRegion, - Method::kRemovePrefix, Method::kRemoveSuffic, + return Methods{Method::kUnknown, + Method::kAppendCord, + Method::kAppendExternalMemory, + Method::kAppendString, + Method::kAssignCord, + Method::kAssignString, + Method::kClear, + Method::kConstructorCord, + Method::kConstructorString, + Method::kFlatten, + Method::kGetAppendRegion, + Method::kMoveAppendCord, + Method::kMoveAssignCord, + Method::kMovePrependCord, + Method::kPrependCord, + Method::kPrependString, + Method::kRemovePrefix, + Method::kRemoveSuffix, Method::kSubCord}; } -- cgit v1.2.3 From a9831f1cbf93fb18dd951453635f488037454ce9 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 3 May 2021 07:37:39 -0700 Subject: Export of internal Abseil changes -- cf88f9cf40eab54c06bca7f20795352ec23bb583 by Derek Mauro : Fixes build with latest glibc Fixes #952 PiperOrigin-RevId: 371693908 -- 99bcd0f4a747ce7a401e23c745adf34d0ec5131b by Samuel Benzaquen : Add support for std::string_view in StrFormat even when absl::string_view != std::string_view. PiperOrigin-RevId: 371693633 -- e35463572149a6c2d4a0d439b9300ce03fd6b96d by Abseil Team : Cmake builds should only install pkg-config when explicitly requested. PiperOrigin-RevId: 371403419 GitOrigin-RevId: cf88f9cf40eab54c06bca7f20795352ec23bb583 Change-Id: I4360a18c638a4d901ff44ab1e0a9d8f321c302ea --- CMake/AbseilHelpers.cmake | 3 ++- absl/debugging/failure_signal_handler.cc | 3 ++- absl/strings/internal/str_format/arg.h | 8 ++++++++ absl/strings/internal/str_format/convert_test.cc | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) (limited to 'absl/debugging') diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake index 1f754392..1a80b5b4 100644 --- a/CMake/AbseilHelpers.cmake +++ b/CMake/AbseilHelpers.cmake @@ -141,7 +141,8 @@ function(absl_cc_library) endif() # Generate a pkg-config file for every library: - if(_build_type STREQUAL "static" OR _build_type STREQUAL "shared") + if((_build_type STREQUAL "static" OR _build_type STREQUAL "shared") + AND ABSL_ENABLE_INSTALL) if(NOT ABSL_CC_LIB_TESTONLY) if(absl_VERSION) set(PC_VERSION "${absl_VERSION}") diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index e458a795..689e5979 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -136,7 +136,8 @@ static bool SetupAlternateStackOnce() { #else const size_t page_mask = sysconf(_SC_PAGESIZE) - 1; #endif - size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask; + size_t stack_size = + (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask; #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) // Account for sanitizer instrumentation requiring additional stack space. diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index 7040c866..3c91be70 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h @@ -122,6 +122,14 @@ StringConvertResult FormatConvertImpl(const std::string& v, StringConvertResult FormatConvertImpl(string_view v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); +#if defined(ABSL_HAVE_STD_STRING_VIEW) && !defined(ABSL_USES_STD_STRING_VIEW) +inline StringConvertResult FormatConvertImpl(std::string_view v, + FormatConversionSpecImpl conv, + FormatSinkImpl* sink) { + return FormatConvertImpl(absl::string_view(v.data(), v.size()), conv, sink); +} +#endif // ABSL_HAVE_STD_STRING_VIEW && !ABSL_USES_STD_STRING_VIEW + ArgConvertResult FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv, diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index 926283cf..91e03609 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc @@ -229,6 +229,9 @@ TEST_F(FormatConvertTest, BasicString) { TestStringConvert(static_cast("hello")); TestStringConvert(std::string("hello")); TestStringConvert(string_view("hello")); +#if defined(ABSL_HAVE_STD_STRING_VIEW) + TestStringConvert(std::string_view("hello")); +#endif // ABSL_HAVE_STD_STRING_VIEW } TEST_F(FormatConvertTest, NullString) { -- cgit v1.2.3 From 18045c4e32cbe6217224f46261b9e2607d6e723d Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 25 May 2021 13:13:33 -0700 Subject: Export of internal Abseil changes -- d74f30ef0da7139c30a24eb6c1776bc0c257e642 by Derek Mauro : Internal change PiperOrigin-RevId: 375779441 -- 25e33cde30d78dbafcb81ee3ce77c3d70c74db5a by Abseil Team : Internal change PiperOrigin-RevId: 375520720 -- 46857d17d4dbc6fbd13a27dd82e14ec814dd117a by Samuel Benzaquen : Add an explicit template parameter barrier to absl::HashOf. PiperOrigin-RevId: 375103300 -- cf2bf52b9a425b0360ed1f46778f0ef1326a3658 by Abseil Team : Improve string_view API compliance with C++17 std::basic_string_view. This adds missing overloads, default values, and constexpr specifiers. PiperOrigin-RevId: 374885658 -- 41e55166dc5bd3ed7bce567c400781585d55e1ce by Derek Mauro : Update CI to GCC 11.1, Bazel 4.0.0, CMake 3.20.2, and LLVM git:7bcc0a1e399d461af7ec013ff33bc330a2de6641 PiperOrigin-RevId: 374858288 GitOrigin-RevId: d74f30ef0da7139c30a24eb6c1776bc0c257e642 Change-Id: I657c815c83522b030495ff54ca327e7012ed151e --- absl/debugging/internal/stacktrace_x86-inl.inc | 7 +- absl/hash/hash.h | 2 +- absl/hash/hash_test.cc | 13 +++ absl/strings/string_view.cc | 37 +++---- absl/strings/string_view.h | 130 +++++++++++++++++++------ absl/strings/string_view_test.cc | 46 ++++++++- ci/linux_docker_containers.sh | 4 +- 7 files changed, 182 insertions(+), 57 deletions(-) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc index bc320ff7..70f79dfc 100644 --- a/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/absl/debugging/internal/stacktrace_x86-inl.inc @@ -132,9 +132,8 @@ static uintptr_t GetFP(const void *vuc) { const uintptr_t bp = 0; const uintptr_t sp = 0; #endif - // Sanity-check that the base pointer is valid. It should be as long as - // SHRINK_WRAP_FRAME_POINTER is not set, but it's possible that some code in - // the process is compiled with --copt=-fomit-frame-pointer or + // Sanity-check that the base pointer is valid. It's possible that some + // code in the process is compiled with --copt=-fomit-frame-pointer or // --copt=-momit-leaf-frame-pointer. // // TODO(bcmills): -momit-leaf-frame-pointer is currently the default @@ -247,7 +246,7 @@ static void **NextStackFrame(void **old_fp, const void *uc) { // using an alternate signal stack. // // TODO(bcmills): The GetFP call should be completely unnecessary when - // SHRINK_WRAP_FRAME_POINTER is set (because we should be back in the thread's + // ENABLE_COMBINED_UNWINDER is set (because we should be back in the thread's // stack by this point), but it is empirically still needed (e.g. when the // stack includes a call to abort). unw_get_reg returns UNW_EBADREG for some // frames. Figure out why GetValidFrameAddr and/or libunwind isn't doing what diff --git a/absl/hash/hash.h b/absl/hash/hash.h index 69c44fde..8282ea53 100644 --- a/absl/hash/hash.h +++ b/absl/hash/hash.h @@ -230,7 +230,7 @@ using Hash = absl::hash_internal::Hash; // The requirement that the arguments match in both type and value is critical. // It means that `a == b` does not necessarily imply `HashOf(a) == HashOf(b)` if // `a` and `b` have different types. For example, `HashOf(2) != HashOf(2.0)`. -template +template size_t HashOf(const Types&... values) { auto tuple = std::tie(values...); return absl::Hash{}(tuple); diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index 02b7733d..b3ddebdd 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc @@ -995,4 +995,17 @@ TEST(HashOf, MatchesHashOfTupleForMultipleArguments) { absl::HashOf(std::make_tuple(hello, world))); } +template +std::true_type HashOfExplicitParameter(decltype(absl::HashOf(0))) { + return {}; +} +template +std::false_type HashOfExplicitParameter(size_t) { + return {}; +} + +TEST(HashOf, CantPassExplicitTemplateParameters) { + EXPECT_FALSE(HashOfExplicitParameter(0)); +} + } // namespace diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc index c5f5de93..d596e08c 100644 --- a/absl/strings/string_view.cc +++ b/absl/strings/string_view.cc @@ -78,8 +78,8 @@ std::ostream& operator<<(std::ostream& o, string_view piece) { return o; } -string_view::size_type string_view::find(string_view s, size_type pos) const - noexcept { +string_view::size_type string_view::find(string_view s, + size_type pos) const noexcept { if (empty() || pos > length_) { if (empty() && pos == 0 && s.empty()) return 0; return npos; @@ -98,8 +98,8 @@ string_view::size_type string_view::find(char c, size_type pos) const noexcept { return result != nullptr ? result - ptr_ : npos; } -string_view::size_type string_view::rfind(string_view s, size_type pos) const - noexcept { +string_view::size_type string_view::rfind(string_view s, + size_type pos) const noexcept { if (length_ < s.length_) return npos; if (s.empty()) return std::min(length_, pos); const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_; @@ -108,8 +108,8 @@ string_view::size_type string_view::rfind(string_view s, size_type pos) const } // Search range is [0..pos] inclusive. If pos == npos, search everything. -string_view::size_type string_view::rfind(char c, size_type pos) const - noexcept { +string_view::size_type string_view::rfind(char c, + size_type pos) const noexcept { // Note: memrchr() is not available on Windows. if (empty()) return npos; for (size_type i = std::min(pos, length_ - 1);; --i) { @@ -121,9 +121,8 @@ string_view::size_type string_view::rfind(char c, size_type pos) const return npos; } -string_view::size_type string_view::find_first_of(string_view s, - size_type pos) const - noexcept { +string_view::size_type string_view::find_first_of( + string_view s, size_type pos) const noexcept { if (empty() || s.empty()) { return npos; } @@ -138,9 +137,8 @@ string_view::size_type string_view::find_first_of(string_view s, return npos; } -string_view::size_type string_view::find_first_not_of(string_view s, - size_type pos) const - noexcept { +string_view::size_type string_view::find_first_not_of( + string_view s, size_type pos) const noexcept { if (empty()) return npos; // Avoid the cost of LookupTable() for a single-character search. if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos); @@ -153,9 +151,8 @@ string_view::size_type string_view::find_first_not_of(string_view s, return npos; } -string_view::size_type string_view::find_first_not_of(char c, - size_type pos) const - noexcept { +string_view::size_type string_view::find_first_not_of( + char c, size_type pos) const noexcept { if (empty()) return npos; for (; pos < length_; ++pos) { if (ptr_[pos] != c) { @@ -180,9 +177,8 @@ string_view::size_type string_view::find_last_of(string_view s, return npos; } -string_view::size_type string_view::find_last_not_of(string_view s, - size_type pos) const - noexcept { +string_view::size_type string_view::find_last_not_of( + string_view s, size_type pos) const noexcept { if (empty()) return npos; size_type i = std::min(pos, length_ - 1); if (s.empty()) return i; @@ -198,9 +194,8 @@ string_view::size_type string_view::find_last_not_of(string_view s, return npos; } -string_view::size_type string_view::find_last_not_of(char c, - size_type pos) const - noexcept { +string_view::size_type string_view::find_last_not_of( + char c, size_type pos) const noexcept { if (empty()) return npos; size_type i = std::min(pos, length_ - 1); for (;; --i) { diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index 1f14a758..968549be 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h @@ -62,6 +62,12 @@ ABSL_NAMESPACE_END #define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp #endif // ABSL_HAVE_BUILTIN(__builtin_memcmp) +#if defined(__cplusplus) && __cplusplus >= 201402L +#define ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR constexpr +#else +#define ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR +#endif + namespace absl { ABSL_NAMESPACE_BEGIN @@ -265,9 +271,7 @@ class string_view { // string_view::size() // // Returns the number of characters in the `string_view`. - constexpr size_type size() const noexcept { - return length_; - } + constexpr size_type size() const noexcept { return length_; } // string_view::length() // @@ -334,7 +338,7 @@ class string_view { // // Removes the first `n` characters from the `string_view`. Note that the // underlying string is not changed, only the view. - void remove_prefix(size_type n) { + ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_prefix(size_type n) { ABSL_HARDENING_ASSERT(n <= length_); ptr_ += n; length_ -= n; @@ -344,7 +348,7 @@ class string_view { // // Removes the last `n` characters from the `string_view`. Note that the // underlying string is not changed, only the view. - void remove_suffix(size_type n) { + ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_suffix(size_type n) { ABSL_HARDENING_ASSERT(n <= length_); length_ -= n; } @@ -352,7 +356,7 @@ class string_view { // string_view::swap() // // Swaps this `string_view` with another `string_view`. - void swap(string_view& s) noexcept { + ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void swap(string_view& s) noexcept { auto t = *this; *this = s; s = t; @@ -389,7 +393,7 @@ class string_view { // `n`) as another string_view. This function throws `std::out_of_bounds` if // `pos > size`. // Use absl::ClippedSubstr if you need a truncating substr operation. - constexpr string_view substr(size_type pos, size_type n = npos) const { + constexpr string_view substr(size_type pos = 0, size_type n = npos) const { return ABSL_PREDICT_FALSE(pos > length_) ? (base_internal::ThrowStdOutOfRange( "absl::string_view::substr"), @@ -413,31 +417,31 @@ class string_view { // Overload of `string_view::compare()` for comparing a substring of the // 'string_view` and another `absl::string_view`. - int compare(size_type pos1, size_type count1, string_view v) const { + constexpr int compare(size_type pos1, size_type count1, string_view v) const { return substr(pos1, count1).compare(v); } // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a substring of another `absl::string_view`. - int compare(size_type pos1, size_type count1, string_view v, size_type pos2, - size_type count2) const { + constexpr int compare(size_type pos1, size_type count1, string_view v, + size_type pos2, size_type count2) const { return substr(pos1, count1).compare(v.substr(pos2, count2)); } // Overload of `string_view::compare()` for comparing a `string_view` and a - // a different C-style string `s`. - int compare(const char* s) const { return compare(string_view(s)); } + // a different C-style string `s`. + constexpr int compare(const char* s) const { return compare(string_view(s)); } // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a different string C-style string `s`. - int compare(size_type pos1, size_type count1, const char* s) const { + constexpr int compare(size_type pos1, size_type count1, const char* s) const { return substr(pos1, count1).compare(string_view(s)); } // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a substring of a different C-style string `s`. - int compare(size_type pos1, size_type count1, const char* s, - size_type count2) const { + constexpr int compare(size_type pos1, size_type count1, const char* s, + size_type count2) const { return substr(pos1, count1).compare(string_view(s, count2)); } @@ -454,48 +458,92 @@ class string_view { // within the `string_view`. size_type find(char c, size_type pos = 0) const noexcept; + // Overload of `string_view::find()` for finding a substring of a different + // C-style string `s` within the `string_view`. + size_type find(const char* s, size_type pos, size_type count) const { + return find(string_view(s, count), pos); + } + + // Overload of `string_view::find()` for finding a different C-style string + // `s` within the `string_view`. + size_type find(const char* s, size_type pos = 0) const { + return find(string_view(s), pos); + } + // string_view::rfind() // // Finds the last occurrence of a substring `s` within the `string_view`, // returning the position of the first character's match, or `npos` if no // match was found. - size_type rfind(string_view s, size_type pos = npos) const - noexcept; + size_type rfind(string_view s, size_type pos = npos) const noexcept; // Overload of `string_view::rfind()` for finding the last given character `c` // within the `string_view`. size_type rfind(char c, size_type pos = npos) const noexcept; + // Overload of `string_view::rfind()` for finding a substring of a different + // C-style string `s` within the `string_view`. + size_type rfind(const char* s, size_type pos, size_type count) const { + return rfind(string_view(s, count), pos); + } + + // Overload of `string_view::rfind()` for finding a different C-style string + // `s` within the `string_view`. + size_type rfind(const char* s, size_type pos = npos) const { + return rfind(string_view(s), pos); + } + // string_view::find_first_of() // // Finds the first occurrence of any of the characters in `s` within the // `string_view`, returning the start position of the match, or `npos` if no // match was found. - size_type find_first_of(string_view s, size_type pos = 0) const - noexcept; + size_type find_first_of(string_view s, size_type pos = 0) const noexcept; // Overload of `string_view::find_first_of()` for finding a character `c` // within the `string_view`. - size_type find_first_of(char c, size_type pos = 0) const - noexcept { + size_type find_first_of(char c, size_type pos = 0) const noexcept { return find(c, pos); } + // Overload of `string_view::find_first_of()` for finding a substring of a + // different C-style string `s` within the `string_view`. + size_type find_first_of(const char* s, size_type pos, + size_type count) const { + return find_first_of(string_view(s, count), pos); + } + + // Overload of `string_view::find_first_of()` for finding a different C-style + // string `s` within the `string_view`. + size_type find_first_of(const char* s, size_type pos = 0) const { + return find_first_of(string_view(s), pos); + } + // string_view::find_last_of() // // Finds the last occurrence of any of the characters in `s` within the // `string_view`, returning the start position of the match, or `npos` if no // match was found. - size_type find_last_of(string_view s, size_type pos = npos) const - noexcept; + size_type find_last_of(string_view s, size_type pos = npos) const noexcept; // Overload of `string_view::find_last_of()` for finding a character `c` // within the `string_view`. - size_type find_last_of(char c, size_type pos = npos) const - noexcept { + size_type find_last_of(char c, size_type pos = npos) const noexcept { return rfind(c, pos); } + // Overload of `string_view::find_last_of()` for finding a substring of a + // different C-style string `s` within the `string_view`. + size_type find_last_of(const char* s, size_type pos, size_type count) const { + return find_last_of(string_view(s, count), pos); + } + + // Overload of `string_view::find_last_of()` for finding a different C-style + // string `s` within the `string_view`. + size_type find_last_of(const char* s, size_type pos = npos) const { + return find_last_of(string_view(s), pos); + } + // string_view::find_first_not_of() // // Finds the first occurrence of any of the characters not in `s` within the @@ -507,18 +555,43 @@ class string_view { // that is not `c` within the `string_view`. size_type find_first_not_of(char c, size_type pos = 0) const noexcept; + // Overload of `string_view::find_first_not_of()` for finding a substring of a + // different C-style string `s` within the `string_view`. + size_type find_first_not_of(const char* s, size_type pos, + size_type count) const { + return find_first_not_of(string_view(s, count), pos); + } + + // Overload of `string_view::find_first_not_of()` for finding a different + // C-style string `s` within the `string_view`. + size_type find_first_not_of(const char* s, size_type pos = 0) const { + return find_first_not_of(string_view(s), pos); + } + // string_view::find_last_not_of() // // Finds the last occurrence of any of the characters not in `s` within the // `string_view`, returning the start position of the last non-match, or // `npos` if no non-match was found. size_type find_last_not_of(string_view s, - size_type pos = npos) const noexcept; + size_type pos = npos) const noexcept; // Overload of `string_view::find_last_not_of()` for finding a character // that is not `c` within the `string_view`. - size_type find_last_not_of(char c, size_type pos = npos) const - noexcept; + size_type find_last_not_of(char c, size_type pos = npos) const noexcept; + + // Overload of `string_view::find_last_not_of()` for finding a substring of a + // different C-style string `s` within the `string_view`. + size_type find_last_not_of(const char* s, size_type pos, + size_type count) const { + return find_last_not_of(string_view(s, count), pos); + } + + // Overload of `string_view::find_last_not_of()` for finding a different + // C-style string `s` within the `string_view`. + size_type find_last_not_of(const char* s, size_type pos = npos) const { + return find_last_not_of(string_view(s), pos); + } private: static constexpr size_type kMaxSize = @@ -596,6 +669,7 @@ std::ostream& operator<<(std::ostream& o, string_view piece); ABSL_NAMESPACE_END } // namespace absl +#undef ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR #undef ABSL_INTERNAL_STRING_VIEW_MEMCMP #endif // ABSL_USES_STD_STRING_VIEW diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc index 643af8f8..2c13dd1c 100644 --- a/absl/strings/string_view_test.cc +++ b/absl/strings/string_view_test.cc @@ -449,6 +449,24 @@ TEST(StringViewTest, STL2) { EXPECT_EQ(d.find('x', 4), absl::string_view::npos); EXPECT_EQ(e.find('x', 7), absl::string_view::npos); + EXPECT_EQ(a.find(b.data(), 1, 0), 1); + EXPECT_EQ(a.find(c.data(), 9, 0), 9); + EXPECT_EQ(a.find(c.data(), absl::string_view::npos, 0), + absl::string_view::npos); + EXPECT_EQ(b.find(c.data(), absl::string_view::npos, 0), + absl::string_view::npos); + // empty string nonsense + EXPECT_EQ(d.find(b.data(), 4, 0), absl::string_view::npos); + EXPECT_EQ(e.find(b.data(), 7, 0), absl::string_view::npos); + + EXPECT_EQ(a.find(b.data(), 1), absl::string_view::npos); + EXPECT_EQ(a.find(c.data(), 9), 23); + EXPECT_EQ(a.find(c.data(), absl::string_view::npos), absl::string_view::npos); + EXPECT_EQ(b.find(c.data(), absl::string_view::npos), absl::string_view::npos); + // empty string nonsense + EXPECT_EQ(d.find(b.data(), 4), absl::string_view::npos); + EXPECT_EQ(e.find(b.data(), 7), absl::string_view::npos); + EXPECT_EQ(a.rfind(b), 0); EXPECT_EQ(a.rfind(b, 1), 0); EXPECT_EQ(a.rfind(c), 23); @@ -490,6 +508,14 @@ TEST(StringViewTest, STL2) { EXPECT_EQ(e.rfind('o'), absl::string_view::npos); EXPECT_EQ(d.rfind('o', 4), absl::string_view::npos); EXPECT_EQ(e.rfind('o', 7), absl::string_view::npos); + + EXPECT_EQ(a.rfind(b.data(), 1, 0), 1); + EXPECT_EQ(a.rfind(c.data(), 22, 0), 22); + EXPECT_EQ(a.rfind(c.data(), 1, 0), 1); + EXPECT_EQ(a.rfind(c.data(), 0, 0), 0); + EXPECT_EQ(b.rfind(c.data(), 0, 0), 0); + EXPECT_EQ(d.rfind(b.data(), 4, 0), 0); + EXPECT_EQ(e.rfind(b.data(), 7, 0), 0); } // Continued from STL2 @@ -678,6 +704,7 @@ TEST(StringViewTest, STL2Substr) { EXPECT_EQ(a.substr(23, 3), c); EXPECT_EQ(a.substr(23, 99), c); EXPECT_EQ(a.substr(0), a); + EXPECT_EQ(a.substr(), a); EXPECT_EQ(a.substr(3, 2), "de"); // empty string nonsense EXPECT_EQ(d.substr(0, 99), e); @@ -1087,7 +1114,24 @@ TEST(StringViewTest, ConstexprCompiles) { EXPECT_EQ(sp_npos, -1); } -TEST(StringViewTest, ConstexprSubstr) { +constexpr char ConstexprMethodsHelper() { +#if defined(__cplusplus) && __cplusplus >= 201402L + absl::string_view str("123", 3); + str.remove_prefix(1); + str.remove_suffix(1); + absl::string_view bar; + str.swap(bar); + return bar.front(); +#else + return '2'; +#endif +} + +TEST(StringViewTest, ConstexprMethods) { + // remove_prefix, remove_suffix, swap + static_assert(ConstexprMethodsHelper() == '2', ""); + + // substr constexpr absl::string_view foobar("foobar", 6); constexpr absl::string_view foo = foobar.substr(0, 3); constexpr absl::string_view bar = foobar.substr(3); diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh index 1c29d9a1..e7eef0fc 100644 --- a/ci/linux_docker_containers.sh +++ b/ci/linux_docker_containers.sh @@ -16,6 +16,6 @@ # Test scripts should source this file to get the identifiers. readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20201026" -readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008" -readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008" +readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20210519" +readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20210519" readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20201015" -- cgit v1.2.3 From ed53ad03abd7baf39dda2ac8037ff3d4f5c533e5 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 2 Jun 2021 13:32:24 -0700 Subject: Export of internal Abseil changes -- b2a781121ff72fb485b7e67539d5e4ff1eb66df2 by Gennadiy Rozental : Consistently use absl::flat_hash_map instead of std::map in Flags implementation. PiperOrigin-RevId: 377132816 -- 9ab83a154d8f22d51fed0092bf94245b5af1f498 by Derek Mauro : Workaround for MSAN being unable to see through getentropy(). https://github.com/google/sanitizers/issues/1173 PiperOrigin-RevId: 377097059 -- 8d28e921442d1b246c26f3200f21027557c47657 by Greg Falcon : Disable stack_consumption_test in tsan builds. A recent tsan change broke the way this test-only utility was counting stack usage. PiperOrigin-RevId: 377053169 GitOrigin-RevId: b2a781121ff72fb485b7e67539d5e4ff1eb66df2 Change-Id: Ib56356f8128f6c083f32b950091f3a56d9e2cd51 --- absl/debugging/BUILD.bazel | 1 + absl/flags/BUILD.bazel | 1 + absl/flags/CMakeLists.txt | 1 + absl/flags/internal/usage.cc | 12 +++++++++--- absl/flags/reflection.cc | 8 ++++++-- absl/random/internal/BUILD.bazel | 1 + absl/random/internal/seed_material.cc | 4 ++++ 7 files changed, 23 insertions(+), 5 deletions(-) (limited to 'absl/debugging') diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index 5385bcb6..2aac0f66 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -344,6 +344,7 @@ cc_test( srcs = ["internal/stack_consumption_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + tags = ["notsan"], deps = [ ":stack_consumption", "//absl/base:core_headers", diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 147249ed..c178b86b 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -259,6 +259,7 @@ cc_library( ":reflection", "//absl/base:config", "//absl/base:core_headers", + "//absl/container:flat_hash_map", "//absl/strings", ], ) diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index caac69cf..827784b1 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -239,6 +239,7 @@ absl_cc_library( absl::flags_private_handle_accessor absl::flags_program_name absl::flags_reflection + absl::flat_hash_map absl::strings absl::synchronization ) diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc index a588c7f7..949709e8 100644 --- a/absl/flags/internal/usage.cc +++ b/absl/flags/internal/usage.cc @@ -245,7 +245,7 @@ void FlagsHelpImpl(std::ostream& out, PerFlagFilter filter_cb, << XMLElement("usage", program_usage_message) << '\n'; } - // Map of package name to + // Ordered map of package name to // map of file name to // vector of flags in the file. // This map is used to output matching flags grouped by package and file @@ -273,20 +273,26 @@ void FlagsHelpImpl(std::ostream& out, PerFlagFilter filter_cb, absl::string_view package_separator; // controls blank lines between packages absl::string_view file_separator; // controls blank lines between files - for (const auto& package : matching_flags) { + for (auto& package : matching_flags) { if (format == HelpFormat::kHumanReadable) { out << package_separator; package_separator = "\n\n"; } file_separator = ""; - for (const auto& flags_in_file : package.second) { + for (auto& flags_in_file : package.second) { if (format == HelpFormat::kHumanReadable) { out << file_separator << " Flags from " << flags_in_file.first << ":\n"; file_separator = "\n"; } + std::sort(std::begin(flags_in_file.second), + std::end(flags_in_file.second), + [](const CommandLineFlag* lhs, const CommandLineFlag* rhs) { + return lhs->Name() < rhs->Name(); + }); + for (const auto* flag : flags_in_file.second) { flags_internal::FlagHelp(out, *flag, format); } diff --git a/absl/flags/reflection.cc b/absl/flags/reflection.cc index 0c761101..dbce4032 100644 --- a/absl/flags/reflection.cc +++ b/absl/flags/reflection.cc @@ -18,11 +18,11 @@ #include #include -#include #include #include "absl/base/config.h" #include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" #include "absl/flags/commandlineflag.h" #include "absl/flags/internal/private_handle_accessor.h" #include "absl/flags/internal/registry.h" @@ -68,7 +68,7 @@ class FlagRegistry { friend void FinalizeRegistry(); // The map from name to flag, for FindFlag(). - using FlagMap = std::map; + using FlagMap = absl::flat_hash_map; using FlagIterator = FlagMap::iterator; using FlagConstIterator = FlagMap::const_iterator; FlagMap flags_; @@ -204,6 +204,10 @@ void FinalizeRegistry() { for (const auto& f : registry.flags_) { registry.flat_flags_.push_back(f.second); } + std::sort(std::begin(registry.flat_flags_), std::end(registry.flat_flags_), + [](const CommandLineFlag* lhs, const CommandLineFlag* rhs) { + return lhs->Name() < rhs->Name(); + }); registry.flags_.clear(); registry.finalized_flags_.store(true, std::memory_order_release); } diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel index 90efe85a..6e06fe9a 100644 --- a/absl/random/internal/BUILD.bazel +++ b/absl/random/internal/BUILD.bazel @@ -82,6 +82,7 @@ cc_library( deps = [ ":fast_uniform_bits", "//absl/base:core_headers", + "//absl/base:dynamic_annotations", "//absl/base:raw_logging_internal", "//absl/strings", "//absl/types:optional", diff --git a/absl/random/internal/seed_material.cc b/absl/random/internal/seed_material.cc index 0fcba509..7c1d9efa 100644 --- a/absl/random/internal/seed_material.cc +++ b/absl/random/internal/seed_material.cc @@ -28,6 +28,7 @@ #include #include +#include "absl/base/dynamic_annotations.h" #include "absl/base/internal/raw_logging.h" #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" @@ -142,6 +143,9 @@ bool ReadSeedMaterialFromGetEntropy(absl::Span values) { if (result < 0) { return false; } + // https://github.com/google/sanitizers/issues/1173 + // MemorySanitizer can't see through getentropy(). + ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(buffer, to_read); buffer += to_read; buffer_size -= to_read; } -- cgit v1.2.3 From 8f92175783c9685045c50f227e7c10f1cddb4d58 Mon Sep 17 00:00:00 2001 From: Florin Crișan Date: Thu, 10 Jun 2021 02:26:40 +0300 Subject: CMake: add option to use Google Test already installed on system (#969) As of this change, you can use `-DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON` to have Abseil use the standard CMake find_package(GTest) mechanism. --- CMake/AbseilHelpers.cmake | 4 +- CMake/README.md | 45 ++++++++++++++ CMakeLists.txt | 39 +++++++++--- absl/algorithm/CMakeLists.txt | 4 +- absl/base/CMakeLists.txt | 58 ++++++++--------- absl/cleanup/CMakeLists.txt | 2 +- absl/container/CMakeLists.txt | 60 +++++++++--------- absl/debugging/CMakeLists.txt | 14 ++--- absl/flags/CMakeLists.txt | 22 +++---- absl/functional/CMakeLists.txt | 4 +- absl/hash/CMakeLists.txt | 8 +-- absl/memory/CMakeLists.txt | 4 +- absl/meta/CMakeLists.txt | 2 +- absl/numeric/CMakeLists.txt | 4 +- absl/random/CMakeLists.txt | 120 ++++++++++++++++++------------------ absl/status/CMakeLists.txt | 4 +- absl/strings/CMakeLists.txt | 80 ++++++++++++------------ absl/synchronization/CMakeLists.txt | 14 ++--- absl/time/CMakeLists.txt | 4 +- absl/types/CMakeLists.txt | 26 ++++---- absl/utility/CMakeLists.txt | 2 +- 21 files changed, 295 insertions(+), 225 deletions(-) (limited to 'absl/debugging') diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake index 1fa57a73..6a64a2c7 100644 --- a/CMake/AbseilHelpers.cmake +++ b/CMake/AbseilHelpers.cmake @@ -336,8 +336,8 @@ endfunction() # "awesome_test.cc" # DEPS # absl::awesome -# gmock -# gtest_main +# GTest::gmock +# GTest::gtest_main # ) function(absl_cc_test) if(NOT BUILD_TESTING) diff --git a/CMake/README.md b/CMake/README.md index 5eee8171..fa8e8d30 100644 --- a/CMake/README.md +++ b/CMake/README.md @@ -99,3 +99,48 @@ absl::synchronization absl::time absl::utility ``` + +## Traditional CMake Set-Up + +For larger projects, it may make sense to use the traditional CMake set-up where you build and install projects separately. + +First, you'd need to build and install Google Test: +``` +cmake -S /source/googletest -B /build/googletest -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/installation/dir -DBUILD_GMOCK=ON +cmake --build /build/googletest --target install +``` + +Then you need to configure and build Abseil. Make sure you enable `ABSL_USE_EXTERNAL_GOOGLETEST` and `ABSL_FIND_GOOGLETEST`. You also need to enable `ABSL_ENABLE_INSTALL` so that you can install Abseil itself. +``` +cmake -S /source/abseil-cpp -B /build/abseil-cpp -DCMAKE_PREFIX_PATH=/installation/dir -DCMAKE_INSTALL_PREFIX=/installation/dir -DABSL_ENABLE_INSTALL=ON -DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON +cmake --build /temporary/build/abseil-cpp +``` + +(`CMAKE_PREFIX_PATH` is where you already have Google Test installed; `CMAKE_INSTALL_PREFIX` is where you want to have Abseil installed; they can be different.) + +Run the tests: +``` +ctest --test-dir /temporary/build/abseil-cpp +``` + +And finally install: +``` +cmake --build /temporary/build/abseil-cpp --target install +``` + +# CMake Option Synposis + +## Enable Standard CMake Installation + +`-DABSL_ENABLE_INSTALL=ON` + +## Google Test Options + +`-DBUILD_TESTING=ON` must be set to enable testing + +- Have Abseil download and build Google Test for you: `-DABSL_USE_EXTERNAL_GOOGLETEST=OFF` (default) + - Download and build latest Google Test: `-DABSL_USE_GOOGLETEST_HEAD=ON` + - Download specific Google Test version (ZIP archive): `-DABSL_GOOGLETEST_DOWNLOAD_URL=https://.../version.zip` + - Use Google Test from specific local directory: `-DABSL_LOCAL_GOOGLETEST_DIR=/path/to/googletest` +- Use Google Test included elsewhere in your project: `-DABSL_USE_EXTERNAL_GOOGLETEST=ON` +- Use standard CMake `find_package(CTest)` to find installed Google Test: `-DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON` diff --git a/CMakeLists.txt b/CMakeLists.txt index d0c6e608..42bcbe10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,9 +102,18 @@ endif() ## pthread find_package(Threads REQUIRED) +include(CMakeDependentOption) + option(ABSL_USE_EXTERNAL_GOOGLETEST "If ON, Abseil will assume that the targets for GoogleTest are already provided by the including project. This makes sense when Abseil is used with add_subproject." OFF) +cmake_dependent_option(ABSL_FIND_GOOGLETEST + "If ON, Abseil will use find_package(GTest) rather than assuming that GoogleTest is already provided by the including project." + ON + "ABSL_USE_EXTERNAL_GOOGLETEST" + OFF) + + option(ABSL_USE_GOOGLETEST_HEAD "If ON, abseil will download HEAD from GoogleTest at config time." OFF) @@ -116,7 +125,15 @@ set(ABSL_LOCAL_GOOGLETEST_DIR "/usr/src/googletest" CACHE PATH if(BUILD_TESTING) ## check targets - if (NOT ABSL_USE_EXTERNAL_GOOGLETEST) + if (ABSL_USE_EXTERNAL_GOOGLETEST) + if (ABSL_FIND_GOOGLETEST) + find_package(GTest REQUIRED) + else() + if (NOT TARGET gtest AND NOT TARGET GTest::gtest) + message(FATAL_ERROR "ABSL_USE_EXTERNAL_GOOGLETEST is ON and ABSL_FIND_GOOGLETEST is OFF, which means that the top-level project must build the Google Test project. However, the target gtest was not found.") + endif() + endif() + else() set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build) if(ABSL_USE_GOOGLETEST_HEAD AND ABSL_GOOGLETEST_DOWNLOAD_URL) message(FATAL_ERROR "Do not set both ABSL_USE_GOOGLETEST_HEAD and ABSL_GOOGLETEST_DOWNLOAD_URL") @@ -134,14 +151,22 @@ if(BUILD_TESTING) include(CMake/Googletest/DownloadGTest.cmake) endif() - check_target(gtest) - check_target(gtest_main) - check_target(gmock) + if (NOT ABSL_FIND_GOOGLETEST) + # When Google Test is included directly rather than through find_package, the aliases are missing. + add_library(GTest::gtest_main ALIAS gtest_main) + add_library(GTest::gtest ALIAS gtest) + add_library(GTest::gmock ALIAS gmock) + endif() + + check_target(GTest::gtest) + check_target(GTest::gtest_main) + check_target(GTest::gmock) + check_target(GTest::gmock_main) list(APPEND ABSL_TEST_COMMON_LIBRARIES - gtest_main - gtest - gmock + GTest::gtest_main + GTest::gtest + GTest::gmock ${CMAKE_THREAD_LIBS_INIT} ) endif() diff --git a/absl/algorithm/CMakeLists.txt b/absl/algorithm/CMakeLists.txt index 56cd0fb8..609d8589 100644 --- a/absl/algorithm/CMakeLists.txt +++ b/absl/algorithm/CMakeLists.txt @@ -35,7 +35,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::algorithm - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -65,5 +65,5 @@ absl_cc_test( absl::core_headers absl::memory absl::span - gmock_main + GTest::gmock_main ) diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 981b8cc0..7d56aa13 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -230,7 +230,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} DEPS absl::config - gtest + GTest::gtest TESTONLY ) @@ -259,7 +259,7 @@ absl_cc_library( absl::meta absl::strings absl::utility - gtest + GTest::gtest TESTONLY ) @@ -273,7 +273,7 @@ absl_cc_test( DEPS absl::exception_safety_testing absl::memory - gtest_main + GTest::gtest_main ) absl_cc_library( @@ -300,8 +300,8 @@ absl_cc_test( absl::atomic_hook_test_helper absl::atomic_hook absl::core_headers - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -314,7 +314,7 @@ absl_cc_test( DEPS absl::base absl::core_headers - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -327,8 +327,8 @@ absl_cc_test( DEPS absl::errno_saver absl::strerror - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -342,7 +342,7 @@ absl_cc_test( absl::base absl::config absl::throw_delegate - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -357,7 +357,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::base_internal - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -371,8 +371,8 @@ absl_cc_test( absl::base_internal absl::memory absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_library( @@ -388,7 +388,7 @@ absl_cc_library( absl::base_internal absl::core_headers absl::synchronization - gtest + GTest::gtest TESTONLY ) @@ -406,7 +406,7 @@ absl_cc_test( absl::config absl::core_headers absl::synchronization - gtest_main + GTest::gtest_main ) absl_cc_library( @@ -435,7 +435,7 @@ absl_cc_test( absl::base absl::config absl::endian - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -448,7 +448,7 @@ absl_cc_test( DEPS absl::config absl::synchronization - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -462,7 +462,7 @@ absl_cc_test( absl::base absl::core_headers absl::synchronization - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -475,7 +475,7 @@ absl_cc_test( DEPS absl::raw_logging_internal absl::strings - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -488,7 +488,7 @@ absl_cc_test( DEPS absl::base absl::synchronization - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -516,7 +516,7 @@ absl_cc_test( absl::core_headers absl::synchronization Threads::Threads - gtest_main + GTest::gtest_main ) absl_cc_library( @@ -543,7 +543,7 @@ absl_cc_test( DEPS absl::exponential_biased absl::strings - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -570,7 +570,7 @@ absl_cc_test( DEPS absl::core_headers absl::periodic_sampler - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -596,7 +596,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::scoped_set_env - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -620,8 +620,8 @@ absl_cc_test( absl::flags_marshalling absl::log_severity absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_library( @@ -651,8 +651,8 @@ absl_cc_test( DEPS absl::strerror absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_library( @@ -677,7 +677,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::fast_type_id - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -690,5 +690,5 @@ absl_cc_test( DEPS absl::core_headers absl::optional - gtest_main + GTest::gtest_main ) diff --git a/absl/cleanup/CMakeLists.txt b/absl/cleanup/CMakeLists.txt index a2dd78a8..26a6d0dc 100644 --- a/absl/cleanup/CMakeLists.txt +++ b/absl/cleanup/CMakeLists.txt @@ -51,5 +51,5 @@ absl_cc_test( absl::cleanup absl::config absl::utility - gmock_main + GTest::gmock_main ) diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 2d7d0e65..91c40154 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt @@ -80,7 +80,7 @@ absl_cc_test( absl::strings absl::test_instance_tracker absl::type_traits - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -109,7 +109,7 @@ absl_cc_test( absl::optional absl::test_instance_tracker absl::utility - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -144,7 +144,7 @@ absl_cc_test( absl::exception_testing absl::hash_testing absl::memory - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -158,7 +158,7 @@ absl_cc_test( absl::fixed_array absl::config absl::exception_safety_testing - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -222,7 +222,7 @@ absl_cc_test( absl::memory absl::raw_logging_internal absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -236,7 +236,7 @@ absl_cc_test( absl::inlined_vector absl::config absl::exception_safety_testing - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -262,7 +262,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::test_instance_tracker - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -297,7 +297,7 @@ absl_cc_test( absl::unordered_map_modifiers_test absl::any absl::raw_logging_internal - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -335,7 +335,7 @@ absl_cc_test( absl::memory absl::raw_logging_internal absl::strings - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -370,7 +370,7 @@ absl_cc_test( absl::unordered_map_lookup_test absl::unordered_map_members_test absl::unordered_map_modifiers_test - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -404,7 +404,7 @@ absl_cc_test( absl::unordered_set_lookup_test absl::unordered_set_members_test absl::unordered_set_modifiers_test - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -433,7 +433,7 @@ absl_cc_test( absl::container_memory absl::strings absl::test_instance_tracker - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -465,7 +465,7 @@ absl_cc_test( absl::hash absl::random_random absl::strings - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -507,7 +507,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::hash_policy_testing - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -531,7 +531,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::hash_policy_traits - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -561,7 +561,7 @@ absl_cc_test( DEPS absl::hashtablez_sampler absl::have_sse - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -618,7 +618,7 @@ absl_cc_test( DEPS absl::hash_policy_traits absl::node_hash_policy - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -693,7 +693,7 @@ absl_cc_test( absl::core_headers absl::raw_logging_internal absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -707,7 +707,7 @@ absl_cc_test( absl::raw_hash_set absl::tracked absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -740,7 +740,7 @@ absl_cc_test( absl::core_headers absl::raw_logging_internal absl::span - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -765,7 +765,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -779,7 +779,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -792,7 +792,7 @@ absl_cc_library( ${ABSL_TEST_COPTS} DEPS absl::type_traits - gmock + GTest::gmock TESTONLY ) @@ -806,7 +806,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -820,7 +820,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -834,7 +834,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -847,7 +847,7 @@ absl_cc_library( ${ABSL_TEST_COPTS} DEPS absl::type_traits - gmock + GTest::gmock TESTONLY ) @@ -861,7 +861,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -877,7 +877,7 @@ absl_cc_test( absl::unordered_set_lookup_test absl::unordered_set_members_test absl::unordered_set_modifiers_test - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -892,5 +892,5 @@ absl_cc_test( absl::unordered_map_lookup_test absl::unordered_map_members_test absl::unordered_map_modifiers_test - gmock_main + GTest::gmock_main ) diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index 074b44cf..bb4d4c92 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -87,7 +87,7 @@ absl_cc_test( absl::memory absl::raw_logging_internal absl::strings - gmock + GTest::gmock ) absl_cc_library( @@ -141,7 +141,7 @@ absl_cc_test( absl::strings absl::raw_logging_internal Threads::Threads - gmock + GTest::gmock ) absl_cc_library( @@ -194,7 +194,7 @@ absl_cc_test( absl::core_headers absl::memory absl::raw_logging_internal - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -261,7 +261,7 @@ absl_cc_test( DEPS absl::leak_check_api_enabled_for_testing absl::base - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -275,7 +275,7 @@ absl_cc_test( DEPS absl::leak_check_api_disabled_for_testing absl::base - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -292,7 +292,7 @@ absl_cc_test( absl::leak_check_disable absl::base absl::raw_logging_internal - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -322,7 +322,7 @@ absl_cc_test( absl::stack_consumption absl::core_headers absl::raw_logging_internal - gmock_main + GTest::gmock_main ) # component target diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index 827784b1..956f70f8 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -310,7 +310,7 @@ absl_cc_test( absl::flags_reflection absl::memory absl::strings - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -322,7 +322,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::flags_config - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -342,7 +342,7 @@ absl_cc_test( absl::flags_reflection absl::strings absl::time - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -354,7 +354,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::flags_marshalling - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -373,7 +373,7 @@ absl_cc_test( absl::scoped_set_env absl::span absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -385,7 +385,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::flags_path_util - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -398,7 +398,7 @@ absl_cc_test( DEPS absl::flags_program_name absl::strings - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -415,7 +415,7 @@ absl_cc_test( absl::flags_usage absl::memory absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -429,7 +429,7 @@ absl_cc_test( absl::base absl::flags_internal absl::time - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -444,7 +444,7 @@ absl_cc_test( absl::flags_path_util absl::flags_program_name absl::strings - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -463,5 +463,5 @@ absl_cc_test( absl::flags_reflection absl::flags_usage absl::strings - gtest + GTest::gtest ) diff --git a/absl/functional/CMakeLists.txt b/absl/functional/CMakeLists.txt index cda914f2..3919e9a1 100644 --- a/absl/functional/CMakeLists.txt +++ b/absl/functional/CMakeLists.txt @@ -39,7 +39,7 @@ absl_cc_test( DEPS absl::bind_front absl::memory - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -68,5 +68,5 @@ absl_cc_test( absl::function_ref absl::memory absl::test_instance_tracker - gmock_main + GTest::gmock_main ) diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index b43bfa54..c82f66f0 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt @@ -52,7 +52,7 @@ absl_cc_library( absl::meta absl::strings absl::variant - gmock + GTest::gmock TESTONLY ) @@ -72,7 +72,7 @@ absl_cc_test( absl::spy_hash_state absl::meta absl::int128 - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -113,7 +113,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::city - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -141,5 +141,5 @@ absl_cc_test( DEPS absl::wyhash absl::strings - gmock_main + GTest::gmock_main ) diff --git a/absl/memory/CMakeLists.txt b/absl/memory/CMakeLists.txt index 78fb7e1b..9d50e1dc 100644 --- a/absl/memory/CMakeLists.txt +++ b/absl/memory/CMakeLists.txt @@ -37,7 +37,7 @@ absl_cc_test( DEPS absl::memory absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -51,5 +51,5 @@ absl_cc_test( absl::memory absl::config absl::exception_safety_testing - gmock_main + GTest::gmock_main ) diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt index 672ead2f..9de4bd37 100644 --- a/absl/meta/CMakeLists.txt +++ b/absl/meta/CMakeLists.txt @@ -35,7 +35,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::type_traits - gmock_main + GTest::gmock_main ) # component target diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt index 781987dc..26df5cf7 100644 --- a/absl/numeric/CMakeLists.txt +++ b/absl/numeric/CMakeLists.txt @@ -38,7 +38,7 @@ absl_cc_test( absl::bits absl::core_headers absl::random_random - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -73,7 +73,7 @@ absl_cc_test( absl::core_headers absl::hash_testing absl::type_traits - gmock_main + GTest::gmock_main ) # component target diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt index 3009a034..9d1c67fb 100644 --- a/absl/random/CMakeLists.txt +++ b/absl/random/CMakeLists.txt @@ -62,8 +62,8 @@ absl_cc_test( absl::random_random absl::random_internal_sequence_urbg absl::fast_type_id - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -119,8 +119,8 @@ absl_cc_library( absl::type_traits absl::utility absl::variant - gmock - gtest + GTest::gmock + GTest::gtest TESTONLY ) @@ -136,8 +136,8 @@ absl_cc_test( DEPS absl::random_mocking_bit_gen absl::random_random - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -153,8 +153,8 @@ absl_cc_test( absl::random_bit_gen_ref absl::random_mocking_bit_gen absl::random_random - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_library( @@ -245,8 +245,8 @@ absl_cc_test( absl::random_random absl::random_internal_sequence_urbg absl::random_internal_pcg_engine - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -268,8 +268,8 @@ absl_cc_test( absl::raw_logging_internal absl::strings absl::str_format - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -285,8 +285,8 @@ absl_cc_test( absl::random_distributions absl::random_random absl::random_internal_distribution_test_util - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -301,8 +301,8 @@ absl_cc_test( absl::random_distributions absl::random_random absl::raw_logging_internal - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -322,8 +322,8 @@ absl_cc_test( absl::raw_logging_internal absl::strings absl::str_format - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -343,8 +343,8 @@ absl_cc_test( absl::random_random absl::raw_logging_internal absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -367,8 +367,8 @@ absl_cc_test( absl::raw_logging_internal absl::strings absl::str_format - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -391,8 +391,8 @@ absl_cc_test( absl::raw_logging_internal absl::strings absl::str_format - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -414,8 +414,8 @@ absl_cc_test( absl::raw_logging_internal absl::strings absl::str_format - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -435,8 +435,8 @@ absl_cc_test( absl::random_random absl::raw_logging_internal absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -456,8 +456,8 @@ absl_cc_test( absl::random_internal_sequence_urbg absl::random_random absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -477,8 +477,8 @@ absl_cc_test( absl::random_random absl::raw_logging_internal absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -492,7 +492,7 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::random_random - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -508,8 +508,8 @@ absl_cc_test( absl::random_seed_sequences absl::random_internal_nonsecure_base absl::random_random - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -894,7 +894,7 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::random_internal_traits - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -911,7 +911,7 @@ absl_cc_test( absl::bits absl::flags absl::random_internal_generate_real - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -926,7 +926,7 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::random_internal_distribution_test_util - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -941,7 +941,7 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::random_internal_fastmath - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -957,8 +957,8 @@ absl_cc_test( DEPS absl::random_internal_explicit_seed_seq absl::random_seed_sequences - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -973,8 +973,8 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::random_internal_salted_seed_seq - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -990,7 +990,7 @@ absl_cc_test( DEPS absl::core_headers absl::random_internal_distribution_test_util - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1005,7 +1005,7 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::random_internal_fast_uniform_bits - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1024,7 +1024,7 @@ absl_cc_test( absl::random_distributions absl::random_seed_sequences absl::strings - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1039,8 +1039,8 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::random_internal_seed_material - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1057,7 +1057,7 @@ absl_cc_test( absl::random_internal_pool_urbg absl::span absl::type_traits - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1074,8 +1074,8 @@ absl_cc_test( absl::random_internal_explicit_seed_seq absl::random_internal_pcg_engine absl::time - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1094,8 +1094,8 @@ absl_cc_test( absl::raw_logging_internal absl::strings absl::time - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1111,7 +1111,7 @@ absl_cc_test( DEPS absl::random_internal_randen absl::type_traits - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1127,7 +1127,7 @@ absl_cc_test( DEPS absl::endian absl::random_internal_randen_slow - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1146,8 +1146,8 @@ absl_cc_test( absl::random_internal_randen_hwaes_impl absl::raw_logging_internal absl::str_format - gmock - gtest + GTest::gmock + GTest::gtest ) # Internal-only target, do not depend on directly. @@ -1178,7 +1178,7 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::random_internal_uniform_helper - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1193,7 +1193,7 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::random_internal_iostream_state_saver - gtest_main + GTest::gtest_main ) # Internal-only target, do not depend on directly. @@ -1210,5 +1210,5 @@ absl_cc_test( absl::random_internal_wide_multiply absl::bits absl::int128 - gtest_main + GTest::gtest_main ) diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt index f0d798a3..1248dff0 100644 --- a/absl/status/CMakeLists.txt +++ b/absl/status/CMakeLists.txt @@ -50,7 +50,7 @@ absl_cc_test( DEPS absl::status absl::strings - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -84,5 +84,5 @@ absl_cc_test( DEPS absl::status absl::statusor - gmock_main + GTest::gmock_main ) diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index d3f1523c..0246dc38 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -101,7 +101,7 @@ absl_cc_test( DEPS absl::strings absl::base - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -115,7 +115,7 @@ absl_cc_test( absl::strings absl::core_headers absl::fixed_array - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -128,7 +128,7 @@ absl_cc_test( DEPS absl::strings absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -142,7 +142,7 @@ absl_cc_test( DEPS absl::strings absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -156,7 +156,7 @@ absl_cc_test( absl::strings_internal absl::base absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -169,7 +169,7 @@ absl_cc_test( DEPS absl::strings absl::type_traits - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -184,7 +184,7 @@ absl_cc_test( absl::config absl::core_headers absl::dynamic_annotations - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -197,7 +197,7 @@ absl_cc_test( DEPS absl::strings absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -209,7 +209,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -226,7 +226,7 @@ absl_cc_test( absl::btree absl::flat_hash_map absl::node_hash_map - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -238,7 +238,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::strings_internal - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -253,7 +253,7 @@ absl_cc_test( absl::base absl::core_headers absl::type_traits - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -268,7 +268,7 @@ absl_cc_test( absl::base absl::core_headers absl::memory - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -281,7 +281,7 @@ absl_cc_test( DEPS absl::strings absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -301,7 +301,7 @@ absl_cc_test( absl::random_random absl::random_distributions absl::strings_internal - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -314,7 +314,7 @@ absl_cc_test( DEPS absl::strings absl::base - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -326,7 +326,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::strings_internal - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -340,7 +340,7 @@ absl_cc_test( absl::strings absl::str_format absl::pow10_helper - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -355,7 +355,7 @@ absl_cc_test( absl::strings absl::config absl::raw_logging_internal - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -370,7 +370,7 @@ absl_cc_test( DEPS absl::strings absl::config - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -428,7 +428,7 @@ absl_cc_test( absl::cord absl::strings absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -442,7 +442,7 @@ absl_cc_test( absl::str_format absl::str_format_internal absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -455,7 +455,7 @@ absl_cc_test( DEPS absl::str_format absl::str_format_internal - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -467,7 +467,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::str_format_internal - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -479,7 +479,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::str_format - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -494,7 +494,7 @@ absl_cc_test( absl::str_format_internal absl::raw_logging_internal absl::int128 - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -507,7 +507,7 @@ absl_cc_test( DEPS absl::str_format_internal absl::cord - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -520,7 +520,7 @@ absl_cc_test( DEPS absl::str_format_internal absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -547,7 +547,7 @@ absl_cc_test( DEPS absl::pow10_helper absl::str_format - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -600,7 +600,7 @@ absl_cc_test( absl::cordz_update_tracker absl::core_headers absl::synchronization - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -628,7 +628,7 @@ absl_cc_test( absl::config absl::cordz_functions absl::cordz_test_helpers - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -675,7 +675,7 @@ absl_cc_test( absl::random_distributions absl::synchronization absl::time - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -722,7 +722,7 @@ absl_cc_test( absl::span absl::stacktrace absl::symbolize - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -742,7 +742,7 @@ absl_cc_test( absl::cordz_update_scope absl::cordz_update_tracker absl::thread_pool - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -780,7 +780,7 @@ absl_cc_test( absl::synchronization absl::thread_pool absl::time - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -813,7 +813,7 @@ absl_cc_test( absl::cordz_update_scope absl::cordz_update_tracker absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -899,7 +899,7 @@ absl_cc_test( absl::endian absl::raw_logging_internal absl::fixed_array - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -916,7 +916,7 @@ absl_cc_test( absl::core_headers absl::raw_logging_internal absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -931,7 +931,7 @@ absl_cc_test( absl::cord_internal absl::core_headers absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -955,5 +955,5 @@ absl_cc_test( absl::core_headers absl::raw_logging_internal absl::strings - gmock_main + GTest::gmock_main ) diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt index e633d0bf..605efe2d 100644 --- a/absl/synchronization/CMakeLists.txt +++ b/absl/synchronization/CMakeLists.txt @@ -95,7 +95,7 @@ absl_cc_test( DEPS absl::synchronization absl::time - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -108,7 +108,7 @@ absl_cc_test( DEPS absl::synchronization absl::time - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -122,7 +122,7 @@ absl_cc_test( absl::graphcycles_internal absl::core_headers absl::raw_logging_internal - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -154,7 +154,7 @@ absl_cc_test( absl::memory absl::raw_logging_internal absl::time - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -167,7 +167,7 @@ absl_cc_test( DEPS absl::synchronization absl::time - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -183,7 +183,7 @@ absl_cc_library( absl::config absl::strings absl::time - gmock + GTest::gmock TESTONLY ) @@ -199,7 +199,7 @@ absl_cc_test( absl::synchronization absl::strings absl::time - gmock_main + GTest::gmock_main ) absl_cc_test( diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt index 00bdd499..f6ff8bd1 100644 --- a/absl/time/CMakeLists.txt +++ b/absl/time/CMakeLists.txt @@ -102,7 +102,7 @@ absl_cc_library( absl::config absl::raw_logging_internal absl::time_zone - gmock + GTest::gmock TESTONLY ) @@ -124,5 +124,5 @@ absl_cc_test( absl::config absl::core_headers absl::time_zone - gmock_main + GTest::gmock_main ) diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index c356b211..d7e8614e 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt @@ -69,7 +69,7 @@ absl_cc_test( absl::exception_testing absl::raw_logging_internal absl::test_instance_tracker - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -85,7 +85,7 @@ absl_cc_test( absl::exception_testing absl::raw_logging_internal absl::test_instance_tracker - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -99,7 +99,7 @@ absl_cc_test( absl::any absl::config absl::exception_safety_testing - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -136,7 +136,7 @@ absl_cc_test( absl::inlined_vector absl::hash_testing absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -156,7 +156,7 @@ absl_cc_test( absl::inlined_vector absl::hash_testing absl::strings - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -222,7 +222,7 @@ absl_cc_test( absl::raw_logging_internal absl::strings absl::type_traits - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -236,7 +236,7 @@ absl_cc_test( absl::optional absl::config absl::exception_safety_testing - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -258,7 +258,7 @@ absl_cc_library( absl::type_traits absl::strings absl::utility - gmock_main + GTest::gmock_main TESTONLY ) @@ -275,7 +275,7 @@ absl_cc_test( DEPS absl::conformance_testing absl::type_traits - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -288,7 +288,7 @@ absl_cc_test( DEPS absl::conformance_testing absl::type_traits - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -324,7 +324,7 @@ absl_cc_test( absl::memory absl::type_traits absl::strings - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -350,7 +350,7 @@ absl_cc_test( DEPS absl::base absl::compare - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -365,5 +365,5 @@ absl_cc_test( absl::config absl::exception_safety_testing absl::memory - gmock_main + GTest::gmock_main ) diff --git a/absl/utility/CMakeLists.txt b/absl/utility/CMakeLists.txt index e1edd19a..865b758f 100644 --- a/absl/utility/CMakeLists.txt +++ b/absl/utility/CMakeLists.txt @@ -40,5 +40,5 @@ absl_cc_test( absl::core_headers absl::memory absl::strings - gmock_main + GTest::gmock_main ) -- cgit v1.2.3 From 4bb739310c0257bedc41bfe2824c3f2860398a65 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 27 Jul 2021 11:15:36 -0700 Subject: Export of internal Abseil changes -- 69b5d0b2a5adb49a53e51f9da6848eaa484242fe by Derek Mauro : Changes the absl::Duration factory functions to disallow types that are convertible to int or double, instead requiring that the argument itself is indeed an integer or a floating-point number. This will prevent callers from passing arguments, such as std::atomic. This change is an API break. Information and a tool to fix issues can be found at https://abseil.io/docs/cpp/tools/upgrades/duration-conversions PiperOrigin-RevId: 387153494 -- 786063e438ab6a55ac4baa88ad4d20a8293be52a by Evan Brown : Make ctrl_t be an enum class. This adds type safety, and also when strict aliasing is enabled, the compiler will know that control bytes can't alias non-control bytes. Also make H2() return h2_t. PiperOrigin-RevId: 387120717 -- 7e537aabec1c255d6e7c9d21232c597c1c2077bf by Evan Brown : Add some missing `const` keywords to ctrl_t* function parameters. PiperOrigin-RevId: 386976062 -- da53ac6d91cabd951e81dd0a145e1e52b918955f by Martijn Vels : Change Seek and InitOffset to return nullptr instead of assert / fail. This makes it consistent with the rest of the API (Next, Previous, Skip) and hardens it against invariants that are harder (or less likey) to be upheld correctly by the caller. PiperOrigin-RevId: 386963283 -- a4d1faac020d5025edf53ce81808e5db68da7d89 by Abseil Team : PC / Backtrace / Symbolization for Emscripten. PiperOrigin-RevId: 386957724 -- 97f2c47d83ba9d3ac89e1f55bd06897686ffd063 by Martijn Vels : Fix static casts ([-Wimplicit-int-conversion]) PiperOrigin-RevId: 386951646 -- 9530c795248543817cbc4013953baa09c35f5e1a by Abseil Team : Fix incorrect header guard in cord_rep_btree_navigator.h PiperOrigin-RevId: 386907904 -- 90ce5872406df2b7f4c428683741dc13a572267e by Abseil Team : Small grammar fixes for some StatusCode descriptions. PiperOrigin-RevId: 386906217 -- b30a2fd777f12a04a4d512f37a34614b0d05ce99 by Derek Mauro : Skip length checking when constructing absl::string_view from std::string. The length check causes unnecessary code bloat. PiperOrigin-RevId: 386857974 -- fa171536c359bfa2a1b80297e844519bb9ee7791 by Martijn Vels : Introduce CordRepBtreeNavigator CordRepBtreeNavigator implements bi-directional navigation over all data edges stored inside a Cord Btree. PiperOrigin-RevId: 386519102 GitOrigin-RevId: 69b5d0b2a5adb49a53e51f9da6848eaa484242fe Change-Id: I1b35188d66133f8cb73d346bc5564aac4e0b3e80 --- CMake/AbseilDll.cmake | 2 + absl/container/internal/raw_hash_set.cc | 10 +- absl/container/internal/raw_hash_set.h | 106 ++++--- absl/container/internal/raw_hash_set_benchmark.cc | 25 +- absl/container/internal/raw_hash_set_test.cc | 57 ++-- absl/debugging/BUILD.bazel | 2 + absl/debugging/CMakeLists.txt | 2 + absl/debugging/internal/stacktrace_config.h | 5 +- .../internal/stacktrace_emscripten-inl.inc | 110 +++++++ absl/debugging/internal/symbolize.h | 6 + absl/debugging/stacktrace.cc | 1 + absl/debugging/symbolize.cc | 2 + absl/debugging/symbolize_emscripten.inc | 72 +++++ absl/debugging/symbolize_test.cc | 31 +- absl/status/status.h | 23 +- absl/strings/BUILD.bazel | 18 ++ absl/strings/CMakeLists.txt | 20 ++ absl/strings/internal/cord_rep_btree.h | 6 +- absl/strings/internal/cord_rep_btree_navigator.cc | 185 ++++++++++++ absl/strings/internal/cord_rep_btree_navigator.h | 265 +++++++++++++++++ .../internal/cord_rep_btree_navigator_test.cc | 325 +++++++++++++++++++++ absl/strings/string_view.h | 10 +- absl/time/time.h | 68 +++-- 23 files changed, 1215 insertions(+), 136 deletions(-) create mode 100644 absl/debugging/internal/stacktrace_emscripten-inl.inc create mode 100644 absl/debugging/symbolize_emscripten.inc create mode 100644 absl/strings/internal/cord_rep_btree_navigator.cc create mode 100644 absl/strings/internal/cord_rep_btree_navigator.h create mode 100644 absl/strings/internal/cord_rep_btree_navigator_test.cc (limited to 'absl/debugging') diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 65014bfb..66c9e395 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -207,6 +207,8 @@ set(ABSL_INTERNAL_DLL_FILES "strings/internal/cord_rep_consume.cc" "strings/internal/cord_rep_btree.cc" "strings/internal/cord_rep_btree.h" + "strings/internal/cord_rep_btree_navigator.cc" + "strings/internal/cord_rep_btree_navigator.h" "strings/internal/cord_rep_flat.h" "strings/internal/cord_rep_ring.cc" "strings/internal/cord_rep_ring.h" diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index f5a9ce68..a5dee6aa 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -37,25 +37,23 @@ inline size_t RandomSeed() { return value ^ static_cast(reinterpret_cast(&counter)); } -bool ShouldInsertBackwards(size_t hash, ctrl_t* ctrl) { +bool ShouldInsertBackwards(size_t hash, const ctrl_t* ctrl) { // To avoid problems with weak hashes and single bit tests, we use % 13. // TODO(kfm,sbenza): revisit after we do unconditional mixing return (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6; } -void ConvertDeletedToEmptyAndFullToDeleted( - ctrl_t* ctrl, size_t capacity) { - assert(ctrl[capacity] == kSentinel); +void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) { + assert(ctrl[capacity] == ctrl_t::kSentinel); assert(IsValidCapacity(capacity)); for (ctrl_t* pos = ctrl; pos < ctrl + capacity; pos += Group::kWidth) { Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos); } // Copy the cloned ctrl bytes. std::memcpy(ctrl + capacity + 1, ctrl, NumClonedBytes()); - ctrl[capacity] = kSentinel; + ctrl[capacity] = ctrl_t::kSentinel; } - } // namespace container_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 675c9148..d7783263 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -252,48 +252,57 @@ class BitMask { T mask_; }; -using ctrl_t = signed char; using h2_t = uint8_t; // The values here are selected for maximum performance. See the static asserts -// below for details. -enum Ctrl : ctrl_t { +// below for details. We use an enum class so that when strict aliasing is +// enabled, the compiler knows ctrl_t doesn't alias other types. +enum class ctrl_t : int8_t { kEmpty = -128, // 0b10000000 kDeleted = -2, // 0b11111110 kSentinel = -1, // 0b11111111 }; static_assert( - kEmpty & kDeleted & kSentinel & 0x80, + (static_cast(ctrl_t::kEmpty) & + static_cast(ctrl_t::kDeleted) & + static_cast(ctrl_t::kSentinel) & 0x80) != 0, "Special markers need to have the MSB to make checking for them efficient"); -static_assert(kEmpty < kSentinel && kDeleted < kSentinel, - "kEmpty and kDeleted must be smaller than kSentinel to make the " - "SIMD test of IsEmptyOrDeleted() efficient"); -static_assert(kSentinel == -1, - "kSentinel must be -1 to elide loading it from memory into SIMD " - "registers (pcmpeqd xmm, xmm)"); -static_assert(kEmpty == -128, - "kEmpty must be -128 to make the SIMD check for its " +static_assert( + ctrl_t::kEmpty < ctrl_t::kSentinel && ctrl_t::kDeleted < ctrl_t::kSentinel, + "ctrl_t::kEmpty and ctrl_t::kDeleted must be smaller than " + "ctrl_t::kSentinel to make the SIMD test of IsEmptyOrDeleted() efficient"); +static_assert( + ctrl_t::kSentinel == static_cast(-1), + "ctrl_t::kSentinel must be -1 to elide loading it from memory into SIMD " + "registers (pcmpeqd xmm, xmm)"); +static_assert(ctrl_t::kEmpty == static_cast(-128), + "ctrl_t::kEmpty must be -128 to make the SIMD check for its " "existence efficient (psignb xmm, xmm)"); -static_assert(~kEmpty & ~kDeleted & kSentinel & 0x7F, - "kEmpty and kDeleted must share an unset bit that is not shared " - "by kSentinel to make the scalar test for MatchEmptyOrDeleted() " - "efficient"); -static_assert(kDeleted == -2, - "kDeleted must be -2 to make the implementation of " +static_assert( + (~static_cast(ctrl_t::kEmpty) & + ~static_cast(ctrl_t::kDeleted) & + static_cast(ctrl_t::kSentinel) & 0x7F) != 0, + "ctrl_t::kEmpty and ctrl_t::kDeleted must share an unset bit that is not " + "shared by ctrl_t::kSentinel to make the scalar test for " + "MatchEmptyOrDeleted() efficient"); +static_assert(ctrl_t::kDeleted == static_cast(-2), + "ctrl_t::kDeleted must be -2 to make the implementation of " "ConvertSpecialToEmptyAndFullToDeleted efficient"); // A single block of empty control bytes for tables without any slots allocated. // This enables removing a branch in the hot path of find(). inline ctrl_t* EmptyGroup() { alignas(16) static constexpr ctrl_t empty_group[] = { - kSentinel, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, - kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty}; + ctrl_t::kSentinel, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, + ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, + ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, + ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty}; return const_cast(empty_group); } // Mixes a randomly generated per-process seed with `hash` and `ctrl` to // randomize insertion order within groups. -bool ShouldInsertBackwards(size_t hash, ctrl_t* ctrl); +bool ShouldInsertBackwards(size_t hash, const ctrl_t* ctrl); // Returns a hash seed. // @@ -309,12 +318,12 @@ inline size_t HashSeed(const ctrl_t* ctrl) { inline size_t H1(size_t hash, const ctrl_t* ctrl) { return (hash >> 7) ^ HashSeed(ctrl); } -inline ctrl_t H2(size_t hash) { return hash & 0x7F; } +inline h2_t H2(size_t hash) { return hash & 0x7F; } -inline bool IsEmpty(ctrl_t c) { return c == kEmpty; } -inline bool IsFull(ctrl_t c) { return c >= 0; } -inline bool IsDeleted(ctrl_t c) { return c == kDeleted; } -inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; } +inline bool IsEmpty(ctrl_t c) { return c == ctrl_t::kEmpty; } +inline bool IsFull(ctrl_t c) { return c >= static_cast(0); } +inline bool IsDeleted(ctrl_t c) { return c == ctrl_t::kDeleted; } +inline bool IsEmptyOrDeleted(ctrl_t c) { return c < ctrl_t::kSentinel; } #if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2 @@ -351,24 +360,24 @@ struct GroupSse2Impl { // Returns a bitmask representing the positions of empty slots. BitMask MatchEmpty() const { #if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 - // This only works because kEmpty is -128. + // This only works because ctrl_t::kEmpty is -128. return BitMask( _mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl))); #else - return Match(static_cast(kEmpty)); + return Match(static_cast(ctrl_t::kEmpty)); #endif } // Returns a bitmask representing the positions of empty or deleted slots. BitMask MatchEmptyOrDeleted() const { - auto special = _mm_set1_epi8(kSentinel); + auto special = _mm_set1_epi8(static_cast(ctrl_t::kSentinel)); return BitMask( _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))); } // Returns the number of trailing empty or deleted elements in the group. uint32_t CountLeadingEmptyOrDeleted() const { - auto special = _mm_set1_epi8(kSentinel); + auto special = _mm_set1_epi8(static_cast(ctrl_t::kSentinel)); return TrailingZeros(static_cast( _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1)); } @@ -403,7 +412,7 @@ struct GroupPortableImpl { // // Caveat: there are false positives but: // - they only occur if there is a real match - // - they never occur on kEmpty, kDeleted, kSentinel + // - they never occur on ctrl_t::kEmpty, ctrl_t::kDeleted, ctrl_t::kSentinel // - they will be handled gracefully by subsequent checks in code // // Example: @@ -459,8 +468,8 @@ inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } // PRECONDITION: // IsValidCapacity(capacity) -// ctrl[capacity] == kSentinel -// ctrl[i] != kSentinel for all i < capacity +// ctrl[capacity] == ctrl_t::kSentinel +// ctrl[i] != ctrl_t::kSentinel for all i < capacity // Applies mapping for every byte in ctrl: // DELETED -> EMPTY // EMPTY -> EMPTY @@ -545,27 +554,28 @@ struct FindInfo { // This is important to make 1 a valid capacity. // // - In small mode only the first `capacity()` control bytes after the -// sentinel are valid. The rest contain dummy kEmpty values that do not +// sentinel are valid. The rest contain dummy ctrl_t::kEmpty values that do not // represent a real slot. This is important to take into account on // find_first_non_full(), where we never try ShouldInsertBackwards() for // small tables. inline bool is_small(size_t capacity) { return capacity < Group::kWidth - 1; } -inline probe_seq probe(ctrl_t* ctrl, size_t hash, +inline probe_seq probe(const ctrl_t* ctrl, size_t hash, size_t capacity) { return probe_seq(H1(hash, ctrl), capacity); } // Probes the raw_hash_set with the probe sequence for hash and returns the // pointer to the first empty or deleted slot. -// NOTE: this function must work with tables having both kEmpty and kDelete -// in one group. Such tables appears during drop_deletes_without_resize. +// NOTE: this function must work with tables having both ctrl_t::kEmpty and +// ctrl_t::kDeleted in one group. Such tables appears during +// drop_deletes_without_resize. // // This function is very useful when insertions happen and: // - the input is already a set // - there are enough slots // - the element with the hash is not in the table -inline FindInfo find_first_non_full(ctrl_t* ctrl, size_t hash, +inline FindInfo find_first_non_full(const ctrl_t* ctrl, size_t hash, size_t capacity) { auto seq = probe(ctrl, hash, capacity); while (true) { @@ -588,11 +598,12 @@ inline FindInfo find_first_non_full(ctrl_t* ctrl, size_t hash, } } -// Reset all ctrl bytes back to kEmpty, except the sentinel. +// Reset all ctrl bytes back to ctrl_t::kEmpty, except the sentinel. inline void ResetCtrl(size_t capacity, ctrl_t* ctrl, const void* slot, size_t slot_size) { - std::memset(ctrl, kEmpty, capacity + 1 + NumClonedBytes()); - ctrl[capacity] = kSentinel; + std::memset(ctrl, static_cast(ctrl_t::kEmpty), + capacity + 1 + NumClonedBytes()); + ctrl[capacity] = ctrl_t::kSentinel; SanitizerPoisonMemoryRegion(slot, slot_size * capacity); } @@ -613,6 +624,11 @@ inline void SetCtrl(size_t i, ctrl_t h, size_t capacity, ctrl_t* ctrl, ctrl[((i - NumClonedBytes()) & capacity) + (NumClonedBytes() & capacity)] = h; } +inline void SetCtrl(size_t i, h2_t h, size_t capacity, ctrl_t* ctrl, + const void* slot, size_t slot_size) { + SetCtrl(i, static_cast(h), capacity, ctrl, slot, slot_size); +} + // Policy: a policy defines how to perform different operations on // the slots of the hashtable (see hash_policy_traits.h for the full interface // of policy). @@ -780,7 +796,7 @@ class raw_hash_set { ctrl_ += shift; slot_ += shift; } - if (ABSL_PREDICT_FALSE(*ctrl_ == kSentinel)) ctrl_ = nullptr; + if (ABSL_PREDICT_FALSE(*ctrl_ == ctrl_t::kSentinel)) ctrl_ = nullptr; } ctrl_t* ctrl_ = nullptr; @@ -1575,8 +1591,8 @@ class raw_hash_set { static_cast(empty_after.TrailingZeros() + empty_before.LeadingZeros()) < Group::kWidth; - SetCtrl(index, was_never_full ? kEmpty : kDeleted, capacity_, ctrl_, slots_, - sizeof(slot_type)); + SetCtrl(index, was_never_full ? ctrl_t::kEmpty : ctrl_t::kDeleted, + capacity_, ctrl_, slots_, sizeof(slot_type)); growth_left() += was_never_full; infoz().RecordErase(); } @@ -1706,7 +1722,7 @@ class raw_hash_set { // right time. SetCtrl(new_i, H2(hash), capacity_, ctrl_, slots_, sizeof(slot_type)); PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slots_ + i); - SetCtrl(i, kEmpty, capacity_, ctrl_, slots_, sizeof(slot_type)); + SetCtrl(i, ctrl_t::kEmpty, capacity_, ctrl_, slots_, sizeof(slot_type)); } else { assert(IsDeleted(ctrl_[new_i])); SetCtrl(new_i, H2(hash), capacity_, ctrl_, slots_, sizeof(slot_type)); diff --git a/absl/container/internal/raw_hash_set_benchmark.cc b/absl/container/internal/raw_hash_set_benchmark.cc index 977ff4c0..c886d3ad 100644 --- a/absl/container/internal/raw_hash_set_benchmark.cc +++ b/absl/container/internal/raw_hash_set_benchmark.cc @@ -315,9 +315,17 @@ void BM_ReserveStringTable(benchmark::State& state) { } BENCHMARK(BM_ReserveStringTable)->Range(128, 4096); +// Like std::iota, except that ctrl_t doesn't support operator++. +template +void Iota(CtrlIter begin, CtrlIter end, int value) { + for (; begin != end; ++begin, ++value) { + *begin = static_cast(value); + } +} + void BM_Group_Match(benchmark::State& state) { std::array group; - std::iota(group.begin(), group.end(), -4); + Iota(group.begin(), group.end(), -4); Group g{group.data()}; h2_t h = 1; for (auto _ : state) { @@ -329,7 +337,7 @@ BENCHMARK(BM_Group_Match); void BM_Group_MatchEmpty(benchmark::State& state) { std::array group; - std::iota(group.begin(), group.end(), -4); + Iota(group.begin(), group.end(), -4); Group g{group.data()}; for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmpty()); } @@ -337,7 +345,7 @@ BENCHMARK(BM_Group_MatchEmpty); void BM_Group_MatchEmptyOrDeleted(benchmark::State& state) { std::array group; - std::iota(group.begin(), group.end(), -4); + Iota(group.begin(), group.end(), -4); Group g{group.data()}; for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmptyOrDeleted()); } @@ -345,7 +353,7 @@ BENCHMARK(BM_Group_MatchEmptyOrDeleted); void BM_Group_CountLeadingEmptyOrDeleted(benchmark::State& state) { std::array group; - std::iota(group.begin(), group.end(), -2); + Iota(group.begin(), group.end(), -2); Group g{group.data()}; for (auto _ : state) ::benchmark::DoNotOptimize(g.CountLeadingEmptyOrDeleted()); @@ -354,7 +362,7 @@ BENCHMARK(BM_Group_CountLeadingEmptyOrDeleted); void BM_Group_MatchFirstEmptyOrDeleted(benchmark::State& state) { std::array group; - std::iota(group.begin(), group.end(), -2); + Iota(group.begin(), group.end(), -2); Group g{group.data()}; for (auto _ : state) ::benchmark::DoNotOptimize(*g.MatchEmptyOrDeleted()); } @@ -363,8 +371,11 @@ BENCHMARK(BM_Group_MatchFirstEmptyOrDeleted); void BM_DropDeletes(benchmark::State& state) { constexpr size_t capacity = (1 << 20) - 1; std::vector ctrl(capacity + 1 + Group::kWidth); - ctrl[capacity] = kSentinel; - std::vector pattern = {kEmpty, 2, kDeleted, 2, kEmpty, 1, kDeleted}; + ctrl[capacity] = ctrl_t::kSentinel; + std::vector pattern = {ctrl_t::kEmpty, static_cast(2), + ctrl_t::kDeleted, static_cast(2), + ctrl_t::kEmpty, static_cast(1), + ctrl_t::kDeleted}; for (size_t i = 0; i != capacity; ++i) { ctrl[i] = pattern[i % pattern.size()]; } diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index a191bff9..4fb31fad 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -58,6 +58,9 @@ using ::testing::Lt; using ::testing::Pair; using ::testing::UnorderedElementsAre; +// Convenience function to static cast to ctrl_t. +ctrl_t CtrlT(int i) { return static_cast(i); } + TEST(Util, NormalizeCapacity) { EXPECT_EQ(1, NormalizeCapacity(0)); EXPECT_EQ(1, NormalizeCapacity(1)); @@ -170,15 +173,19 @@ TEST(Group, EmptyGroup) { TEST(Group, Match) { if (Group::kWidth == 16) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3), + ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7), + CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1), + CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)}; EXPECT_THAT(Group{group}.Match(0), ElementsAre()); EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15)); EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10)); EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9)); EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8)); } else if (Group::kWidth == 8) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2), + ctrl_t::kDeleted, CtrlT(2), CtrlT(1), + ctrl_t::kSentinel, CtrlT(1)}; EXPECT_THAT(Group{group}.Match(0), ElementsAre()); EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7)); EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4)); @@ -189,11 +196,15 @@ TEST(Group, Match) { TEST(Group, MatchEmpty) { if (Group::kWidth == 16) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3), + ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7), + CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1), + CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)}; EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0, 4)); } else if (Group::kWidth == 8) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2), + ctrl_t::kDeleted, CtrlT(2), CtrlT(1), + ctrl_t::kSentinel, CtrlT(1)}; EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0)); } else { FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; @@ -202,11 +213,15 @@ TEST(Group, MatchEmpty) { TEST(Group, MatchEmptyOrDeleted) { if (Group::kWidth == 16) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3), + ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7), + CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1), + CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)}; EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 2, 4)); } else if (Group::kWidth == 8) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2), + ctrl_t::kDeleted, CtrlT(2), CtrlT(1), + ctrl_t::kSentinel, CtrlT(1)}; EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 3)); } else { FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; @@ -217,28 +232,32 @@ TEST(Batch, DropDeletes) { constexpr size_t kCapacity = 63; constexpr size_t kGroupWidth = container_internal::Group::kWidth; std::vector ctrl(kCapacity + 1 + kGroupWidth); - ctrl[kCapacity] = kSentinel; - std::vector pattern = {kEmpty, 2, kDeleted, 2, kEmpty, 1, kDeleted}; + ctrl[kCapacity] = ctrl_t::kSentinel; + std::vector pattern = { + ctrl_t::kEmpty, CtrlT(2), ctrl_t::kDeleted, CtrlT(2), + ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted}; for (size_t i = 0; i != kCapacity; ++i) { ctrl[i] = pattern[i % pattern.size()]; if (i < kGroupWidth - 1) ctrl[i + kCapacity + 1] = pattern[i % pattern.size()]; } ConvertDeletedToEmptyAndFullToDeleted(ctrl.data(), kCapacity); - ASSERT_EQ(ctrl[kCapacity], kSentinel); + ASSERT_EQ(ctrl[kCapacity], ctrl_t::kSentinel); for (size_t i = 0; i < kCapacity + kGroupWidth; ++i) { ctrl_t expected = pattern[i % (kCapacity + 1) % pattern.size()]; - if (i == kCapacity) expected = kSentinel; - if (expected == kDeleted) expected = kEmpty; - if (IsFull(expected)) expected = kDeleted; + if (i == kCapacity) expected = ctrl_t::kSentinel; + if (expected == ctrl_t::kDeleted) expected = ctrl_t::kEmpty; + if (IsFull(expected)) expected = ctrl_t::kDeleted; EXPECT_EQ(ctrl[i], expected) - << i << " " << int{pattern[i % pattern.size()]}; + << i << " " << static_cast(pattern[i % pattern.size()]); } } TEST(Group, CountLeadingEmptyOrDeleted) { - const std::vector empty_examples = {kEmpty, kDeleted}; - const std::vector full_examples = {0, 1, 2, 3, 5, 9, 127, kSentinel}; + const std::vector empty_examples = {ctrl_t::kEmpty, ctrl_t::kDeleted}; + const std::vector full_examples = { + CtrlT(0), CtrlT(1), CtrlT(2), CtrlT(3), + CtrlT(5), CtrlT(9), CtrlT(127), ctrl_t::kSentinel}; for (ctrl_t empty : empty_examples) { std::vector e(Group::kWidth, empty); @@ -871,7 +890,7 @@ TEST(Table, RehashWithNoResize) { const size_t capacity = t.capacity(); // Remove elements from all groups except the first and the last one. - // All elements removed from full groups will be marked as kDeleted. + // All elements removed from full groups will be marked as ctrl_t::kDeleted. const size_t erase_begin = Group::kWidth / 2; const size_t erase_end = (t.size() / Group::kWidth - 1) * Group::kWidth; for (size_t i = erase_begin; i < erase_end; ++i) { diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index 2aac0f66..a8c51a5c 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -34,6 +34,7 @@ cc_library( "internal/stacktrace_aarch64-inl.inc", "internal/stacktrace_arm-inl.inc", "internal/stacktrace_config.h", + "internal/stacktrace_emscripten-inl.inc", "internal/stacktrace_generic-inl.inc", "internal/stacktrace_powerpc-inl.inc", "internal/stacktrace_unimplemented-inl.inc", @@ -57,6 +58,7 @@ cc_library( "symbolize.cc", "symbolize_darwin.inc", "symbolize_elf.inc", + "symbolize_emscripten.inc", "symbolize_unimplemented.inc", "symbolize_win32.inc", ], diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index bb4d4c92..760772f3 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -22,6 +22,7 @@ absl_cc_library( "internal/stacktrace_aarch64-inl.inc" "internal/stacktrace_arm-inl.inc" "internal/stacktrace_config.h" + "internal/stacktrace_emscripten-inl.inc" "internal/stacktrace_generic-inl.inc" "internal/stacktrace_powerpc-inl.inc" "internal/stacktrace_unimplemented-inl.inc" @@ -48,6 +49,7 @@ absl_cc_library( "symbolize.cc" "symbolize_darwin.inc" "symbolize_elf.inc" + "symbolize_emscripten.inc" "symbolize_unimplemented.inc" "symbolize_win32.inc" COPTS diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h index cca410d4..6cceef26 100644 --- a/absl/debugging/internal/stacktrace_config.h +++ b/absl/debugging/internal/stacktrace_config.h @@ -37,6 +37,10 @@ "absl/debugging/internal/stacktrace_generic-inl.inc" #endif +#elif defined(__EMSCRIPTEN__) +#define ABSL_STACKTRACE_INL_HEADER \ + "absl/debugging/internal/stacktrace_emscripten-inl.inc" + #elif defined(__linux__) && !defined(__ANDROID__) #if defined(NO_FRAME_POINTER) && \ @@ -68,7 +72,6 @@ "absl/debugging/internal/stacktrace_generic-inl.inc" #endif #endif - #endif // Fallback to the empty implementation. diff --git a/absl/debugging/internal/stacktrace_emscripten-inl.inc b/absl/debugging/internal/stacktrace_emscripten-inl.inc new file mode 100644 index 00000000..0f444514 --- /dev/null +++ b/absl/debugging/internal/stacktrace_emscripten-inl.inc @@ -0,0 +1,110 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Portable implementation - just use glibc +// +// Note: The glibc implementation may cause a call to malloc. +// This can cause a deadlock in HeapProfiler. + +#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ +#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ + +#include + +#include +#include + +#include "absl/base/attributes.h" +#include "absl/debugging/stacktrace.h" + +extern "C" { +uintptr_t emscripten_stack_snapshot(); +uint32_t emscripten_stack_unwind_buffer(uintptr_t pc, void *buffer, + uint32_t depth); +} + +// Sometimes, we can try to get a stack trace from within a stack +// trace, which can cause a self-deadlock. +// Protect against such reentrant call by failing to get a stack trace. +// +// We use __thread here because the code here is extremely low level -- it is +// called while collecting stack traces from within malloc and mmap, and thus +// can not call anything which might call malloc or mmap itself. +static __thread int recursive = 0; + +// The stack trace function might be invoked very early in the program's +// execution (e.g. from the very first malloc). +// As such, we suppress usage of backtrace during this early stage of execution. +static std::atomic disable_stacktraces(true); // Disabled until healthy. +// Waiting until static initializers run seems to be late enough. +// This file is included into stacktrace.cc so this will only run once. +ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() { + // Check if we can even create stacktraces. If not, bail early and leave + // disable_stacktraces set as-is. + // clang-format off + if (!EM_ASM_INT({ return (typeof wasmOffsetConverter !== 'undefined'); })) { + return 0; + } + // clang-format on + disable_stacktraces.store(false, std::memory_order_relaxed); + return 0; +}(); + +template +static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, + const void *ucp, int *min_dropped_frames) { + if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) { + return 0; + } + ++recursive; + + static_cast(ucp); // Unused. + constexpr int kStackLength = 64; + void *stack[kStackLength]; + + int size; + uintptr_t pc = emscripten_stack_snapshot(); + size = emscripten_stack_unwind_buffer(pc, stack, kStackLength); + + int result_count = size - skip_count; + if (result_count < 0) result_count = 0; + if (result_count > max_depth) result_count = max_depth; + for (int i = 0; i < result_count; i++) result[i] = stack[i + skip_count]; + + if (IS_STACK_FRAMES) { + // No implementation for finding out the stack frame sizes yet. + memset(sizes, 0, sizeof(*sizes) * result_count); + } + if (min_dropped_frames != nullptr) { + if (size - skip_count - max_depth > 0) { + *min_dropped_frames = size - skip_count - max_depth; + } else { + *min_dropped_frames = 0; + } + } + + --recursive; + + return result_count; +} + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace debugging_internal { +bool StackTraceWorksForTest() { return true; } +} // namespace debugging_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h index 4f26130f..8c296f89 100644 --- a/absl/debugging/internal/symbolize.h +++ b/absl/debugging/internal/symbolize.h @@ -68,6 +68,12 @@ ABSL_NAMESPACE_END #define ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE 1 #endif +#ifdef ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE +#error ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE cannot be directly set +#elif defined(__EMSCRIPTEN__) +#define ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE 1 +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc index 1f7c7d82..5358b942 100644 --- a/absl/debugging/stacktrace.cc +++ b/absl/debugging/stacktrace.cc @@ -49,6 +49,7 @@ # include "absl/debugging/internal/stacktrace_aarch64-inl.inc" # include "absl/debugging/internal/stacktrace_arm-inl.inc" +# include "absl/debugging/internal/stacktrace_emscripten-inl.inc" # include "absl/debugging/internal/stacktrace_generic-inl.inc" # include "absl/debugging/internal/stacktrace_powerpc-inl.inc" # include "absl/debugging/internal/stacktrace_unimplemented-inl.inc" diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc index 5e4a25d6..f1abdfda 100644 --- a/absl/debugging/symbolize.cc +++ b/absl/debugging/symbolize.cc @@ -31,6 +31,8 @@ #include "absl/debugging/symbolize_win32.inc" #elif defined(__APPLE__) #include "absl/debugging/symbolize_darwin.inc" +#elif defined(__EMSCRIPTEN__) +#include "absl/debugging/symbolize_emscripten.inc" #else #include "absl/debugging/symbolize_unimplemented.inc" #endif diff --git a/absl/debugging/symbolize_emscripten.inc b/absl/debugging/symbolize_emscripten.inc new file mode 100644 index 00000000..c226c456 --- /dev/null +++ b/absl/debugging/symbolize_emscripten.inc @@ -0,0 +1,72 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include + +#include "absl/base/internal/raw_logging.h" +#include "absl/debugging/internal/demangle.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" + +extern "C" { +const char* emscripten_pc_get_function(const void* pc); +} + +// clang-format off +EM_JS(bool, HaveOffsetConverter, (), + { return typeof wasmOffsetConverter !== 'undefined'; }); +// clang-format on + +namespace absl { +ABSL_NAMESPACE_BEGIN + +void InitializeSymbolizer(const char*) { + if (!HaveOffsetConverter()) { + ABSL_RAW_LOG(INFO, + "Symbolization unavailable. Rebuild with -sWASM=1 " + "and -sUSE_OFFSET_CONVERTER=1."); + } +} + +bool Symbolize(const void* pc, char* out, int out_size) { + // Check if we have the offset converter necessary for pc_get_function. + // Without it, the program will abort(). + if (!HaveOffsetConverter()) { + return false; + } + const char* func_name = emscripten_pc_get_function(pc); + if (func_name == nullptr) { + return false; + } + + strncpy(out, func_name, out_size); + + if (out[out_size - 1] != '\0') { + // strncpy() does not '\0' terminate when it truncates. + static constexpr char kEllipsis[] = "..."; + int ellipsis_size = std::min(sizeof(kEllipsis) - 1, out_size - 1); + memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size); + out[out_size - 1] = '\0'; + } + + return true; +} + +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index 35de02e2..c710a3da 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -146,8 +146,22 @@ static const char *TrySymbolize(void *pc) { return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer)); } -#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \ - defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) +#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \ + defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) || \ + defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE) + +// Test with a return address. +void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { +#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) + void *return_address = __builtin_return_address(0); + const char *symbol = TrySymbolize(return_address); + ABSL_RAW_CHECK(symbol != nullptr, "TestWithReturnAddress failed"); + ABSL_RAW_CHECK(strcmp(symbol, "main") == 0, "TestWithReturnAddress failed"); + std::cout << "TestWithReturnAddress passed" << std::endl; +#endif +} + +#ifndef ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE TEST(Symbolize, Cached) { // Compilers should give us pointers to them. @@ -418,6 +432,7 @@ TEST(Symbolize, ForEachSection) { close(fd); } #endif // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE +#endif // !ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE // x86 specific tests. Uses some inline assembler. extern "C" { @@ -466,17 +481,6 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { } } -// Test with a return address. -void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { -#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) - void *return_address = __builtin_return_address(0); - const char *symbol = TrySymbolize(return_address); - ABSL_RAW_CHECK(symbol != nullptr, "TestWithReturnAddress failed"); - ABSL_RAW_CHECK(strcmp(symbol, "main") == 0, "TestWithReturnAddress failed"); - std::cout << "TestWithReturnAddress passed" << std::endl; -#endif -} - #if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) // Test that we correctly identify bounds of Thumb functions on ARM. // @@ -559,7 +563,6 @@ TEST(Symbolize, SymbolizeWithDemangling) { #endif // !defined(ABSL_CONSUME_DLL) #else // Symbolizer unimplemented - TEST(Symbolize, Unimplemented) { char buf[64]; EXPECT_FALSE(absl::Symbolize((void *)(&nonstatic_func), buf, sizeof(buf))); diff --git a/absl/status/status.h b/absl/status/status.h index 2e05f46e..c5fe0a70 100644 --- a/absl/status/status.h +++ b/absl/status/status.h @@ -80,7 +80,7 @@ ABSL_NAMESPACE_BEGIN // `kFailedPrecondition` if both codes apply. Similarly prefer `kNotFound` or // `kAlreadyExists` over `kFailedPrecondition`. // -// Because these errors may travel RPC boundaries, these codes are tied to the +// Because these errors may cross RPC boundaries, these codes are tied to the // `google.rpc.Code` definitions within // https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto // The string value of these RPC codes is denoted within each enum below. @@ -114,10 +114,10 @@ enum class StatusCode : int { // StatusCode::kInvalidArgument // // kInvalidArgument (gRPC code "INVALID_ARGUMENT") indicates the caller - // specified an invalid argument, such a malformed filename. Note that such - // errors should be narrowly limited to indicate to the invalid nature of the - // arguments themselves. Errors with validly formed arguments that may cause - // errors with the state of the receiving system should be denoted with + // specified an invalid argument, such as a malformed filename. Note that use + // of such errors should be narrowly limited to indicate the invalid nature of + // the arguments themselves. Errors with validly formed arguments that may + // cause errors with the state of the receiving system should be denoted with // `kFailedPrecondition` instead. kInvalidArgument = 3, @@ -137,14 +137,15 @@ enum class StatusCode : int { // // `kNotFound` is useful if a request should be denied for an entire class of // users, such as during a gradual feature rollout or undocumented allow list. - // If, instead, a request should be denied for specific sets of users, such as - // through user-based access control, use `kPermissionDenied` instead. + // If a request should be denied for specific sets of users, such as through + // user-based access control, use `kPermissionDenied` instead. kNotFound = 5, // StatusCode::kAlreadyExists // - // kAlreadyExists (gRPC code "ALREADY_EXISTS") indicates the entity that a - // caller attempted to create (such as file or directory) is already present. + // kAlreadyExists (gRPC code "ALREADY_EXISTS") indicates that the entity a + // caller attempted to create (such as a file or directory) is already + // present. kAlreadyExists = 6, // StatusCode::kPermissionDenied @@ -183,7 +184,7 @@ enum class StatusCode : int { // level (such as when a client-specified test-and-set fails, indicating // the client should restart a read-modify-write sequence). // (c) Use `kFailedPrecondition` if the client should not retry until - // the system state has been explicitly fixed. For example, if an "rmdir" + // the system state has been explicitly fixed. For example, if a "rmdir" // fails because the directory is non-empty, `kFailedPrecondition` // should be returned since the client should not retry unless // the files are deleted from the directory. @@ -283,7 +284,7 @@ std::ostream& operator<<(std::ostream& os, StatusCode code); // absl::StatusToStringMode // // An `absl::StatusToStringMode` is an enumerated type indicating how -// `absl::Status::ToString()` should construct the output string for an non-ok +// `absl::Status::ToString()` should construct the output string for a non-ok // status. enum class StatusToStringMode : int { // ToString will not contain any extra data (such as payloads). It will only diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index c686e05a..7e0245a3 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -270,12 +270,14 @@ cc_library( srcs = [ "internal/cord_internal.cc", "internal/cord_rep_btree.cc", + "internal/cord_rep_btree_navigator.cc", "internal/cord_rep_consume.cc", "internal/cord_rep_ring.cc", ], hdrs = [ "internal/cord_internal.h", "internal/cord_rep_btree.h", + "internal/cord_rep_btree_navigator.h", "internal/cord_rep_consume.h", "internal/cord_rep_flat.h", "internal/cord_rep_ring.h", @@ -318,6 +320,22 @@ cc_test( ], ) +cc_test( + name = "cord_rep_btree_navigator_test", + size = "medium", + srcs = ["internal/cord_rep_btree_navigator_test.cc"], + copts = ABSL_TEST_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":cord_internal", + ":cord_rep_test_util", + ":strings", + "//absl/base:config", + "//absl/base:raw_logging_internal", + "@com_google_googletest//:gtest_main", + ], +) + cc_library( name = "cordz_update_tracker", hdrs = ["internal/cordz_update_tracker.h"], diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 2ddd3c48..e55c035d 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -556,6 +556,7 @@ absl_cc_library( HDRS "internal/cord_internal.h" "internal/cord_rep_btree.h" + "internal/cord_rep_btree_navigator.h" "internal/cord_rep_consume.h" "internal/cord_rep_flat.h" "internal/cord_rep_ring.h" @@ -563,6 +564,7 @@ absl_cc_library( SRCS "internal/cord_internal.cc" "internal/cord_rep_btree.cc" + "internal/cord_rep_btree_navigator.cc" "internal/cord_rep_consume.cc" "internal/cord_rep_ring.cc" COPTS @@ -957,6 +959,24 @@ absl_cc_test( GTest::gmock_main ) +absl_cc_test( + NAME + cord_rep_btree_navigator_test + SRCS + "internal/cord_rep_btree_navigator_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::config + absl::cord_internal + absl::cord_rep_test_util + absl::core_headers + absl::raw_logging_internal + absl::strings + GTest::gmock_main +) + absl_cc_test( NAME cord_ring_test diff --git a/absl/strings/internal/cord_rep_btree.h b/absl/strings/internal/cord_rep_btree.h index f4118fc0..7d854731 100644 --- a/absl/strings/internal/cord_rep_btree.h +++ b/absl/strings/internal/cord_rep_btree.h @@ -507,9 +507,9 @@ inline const CordRepBtree* CordRep::btree() const { inline void CordRepBtree::InitInstance(int height, size_t begin, size_t end) { tag = BTREE; - storage[0] = height; - storage[1] = begin; - storage[2] = end; + storage[0] = static_cast(height); + storage[1] = static_cast(begin); + storage[2] = static_cast(end); } inline CordRep* CordRepBtree::Edge(size_t index) const { diff --git a/absl/strings/internal/cord_rep_btree_navigator.cc b/absl/strings/internal/cord_rep_btree_navigator.cc new file mode 100644 index 00000000..d1f9995d --- /dev/null +++ b/absl/strings/internal/cord_rep_btree_navigator.cc @@ -0,0 +1,185 @@ +// Copyright 2021 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/strings/internal/cord_rep_btree_navigator.h" + +#include + +#include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cord_rep_btree.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + +using ReadResult = CordRepBtreeNavigator::ReadResult; + +namespace { + +// Returns a `CordRepSubstring` from `rep` starting at `offset` of size `n`. +// If `rep` is already a `CordRepSubstring` instance, an adjusted instance is +// created based on the old offset and new offset. +// Adopts a reference on `rep`. Rep must be a valid data edge. Returns +// nullptr if `n == 0`, `rep` if `n == rep->length`. +// Requires `offset < rep->length` and `offset + n <= rep->length`. +// TODO(192061034): move to utility library in internal and optimize for small +// substrings of larger reps. +inline CordRep* Substring(CordRep* rep, size_t offset, size_t n) { + assert(n <= rep->length); + assert(offset < rep->length); + assert(offset <= rep->length - n); + assert(CordRepBtree::IsDataEdge(rep)); + + if (n == 0) return nullptr; + if (n == rep->length) return CordRep::Ref(rep); + + if (rep->tag == SUBSTRING) { + offset += rep->substring()->start; + rep = rep->substring()->child; + } + + CordRepSubstring* substring = new CordRepSubstring(); + substring->length = n; + substring->tag = SUBSTRING; + substring->start = offset; + substring->child = CordRep::Ref(rep); + return substring; +} + +inline CordRep* Substring(CordRep* rep, size_t offset) { + return Substring(rep, offset, rep->length - offset); +} + +} // namespace + +CordRepBtreeNavigator::Position CordRepBtreeNavigator::Skip(size_t n) { + int height = 0; + size_t index = index_[0]; + CordRepBtree* node = node_[0]; + CordRep* edge = node->Edge(index); + + // Overall logic: Find an edge of at least the length we need to skip. + // We consume all edges which are smaller (i.e., must be 100% skipped). + // If we exhausted all edges on the current level, we move one level + // up the tree, and repeat until we either find the edge, or until we hit + // the top of the tree meaning the skip exceeds tree->length. + while (n >= edge->length) { + n -= edge->length; + while (++index == node->end()) { + if (++height > height_) return {nullptr, n}; + node = node_[height]; + index = index_[height]; + } + edge = node->Edge(index); + } + + // If we moved up the tree, descend down to the leaf level, consuming all + // edges that must be skipped. + while (height > 0) { + node = edge->btree(); + index_[height] = index; + node_[--height] = node; + index = node->begin(); + edge = node->Edge(index); + while (n >= edge->length) { + n -= edge->length; + ++index; + assert(index != node->end()); + edge = node->Edge(index); + } + } + index_[0] = index; + return {edge, n}; +} + +ReadResult CordRepBtreeNavigator::Read(size_t edge_offset, size_t n) { + int height = 0; + size_t length = edge_offset + n; + size_t index = index_[0]; + CordRepBtree* node = node_[0]; + CordRep* edge = node->Edge(index); + assert(edge_offset < edge->length); + + if (length < edge->length) { + return {Substring(edge, edge_offset, n), length}; + } + + // Similar to 'Skip', we consume all edges that are inside the 'length' of + // data that needs to be read. If we exhaust the current level, we move one + // level up the tree and repeat until we hit the final edge that must be + // (partially) read. We consume all edges into `subtree`. + CordRepBtree* subtree = CordRepBtree::New(Substring(edge, edge_offset)); + size_t subtree_end = 1; + do { + length -= edge->length; + while (++index == node->end()) { + index_[height] = index; + if (++height > height_) { + subtree->set_end(subtree_end); + if (length == 0) return {subtree, 0}; + CordRep::Unref(subtree); + return {nullptr, length}; + } + if (length != 0) { + subtree->set_end(subtree_end); + subtree = CordRepBtree::New(subtree); + subtree_end = 1; + } + node = node_[height]; + index = index_[height]; + } + edge = node->Edge(index); + if (length >= edge->length) { + subtree->length += edge->length; + subtree->edges_[subtree_end++] = CordRep::Ref(edge); + } + } while (length >= edge->length); + CordRepBtree* tree = subtree; + subtree->length += length; + + // If we moved up the tree, descend down to the leaf level, consuming all + // edges that must be read, adding 'down' nodes to `subtree`. + while (height > 0) { + node = edge->btree(); + index_[height] = index; + node_[--height] = node; + index = node->begin(); + edge = node->Edge(index); + + if (length != 0) { + CordRepBtree* right = CordRepBtree::New(height); + right->length = length; + subtree->edges_[subtree_end++] = right; + subtree->set_end(subtree_end); + subtree = right; + subtree_end = 0; + while (length >= edge->length) { + subtree->edges_[subtree_end++] = CordRep::Ref(edge); + length -= edge->length; + edge = node->Edge(++index); + } + } + } + // Add any (partial) edge still remaining at the leaf level. + if (length != 0) { + subtree->edges_[subtree_end++] = Substring(edge, 0, length); + } + subtree->set_end(subtree_end); + index_[0] = index; + return {tree, length}; +} + +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/strings/internal/cord_rep_btree_navigator.h b/absl/strings/internal/cord_rep_btree_navigator.h new file mode 100644 index 00000000..971b92ed --- /dev/null +++ b/absl/strings/internal/cord_rep_btree_navigator.h @@ -0,0 +1,265 @@ +// Copyright 2021 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_ +#define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_ + +#include +#include + +#include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cord_rep_btree.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + +// CordRepBtreeNavigator is a bi-directional navigator allowing callers to +// navigate all the (leaf) data edges in a CordRepBtree instance. +// +// A CordRepBtreeNavigator instance is by default empty. Callers initialize a +// navigator instance by calling one of `InitFirst()`, `InitLast()` or +// `InitOffset()`, which establishes a current position. Callers can then +// navigate using the `Next`, `Previous`, `Skip` and `Seek` methods. +// +// The navigator instance does not take or adopt a reference on the provided +// `tree` on any of the initialization calls. Callers are responsible for +// guaranteeing the lifecycle of the provided tree. A navigator instance can +// be reset to the empty state by calling `Reset`. +// +// A navigator only keeps positional state on the 'current data edge', it does +// explicitly not keep any 'offset' state. The class does accept and return +// offsets in the `Read()`, `Skip()` and 'Seek()` methods as these would +// otherwise put a big burden on callers. Callers are expected to maintain +// (returned) offset info if they require such granular state. +class CordRepBtreeNavigator { + public: + // The logical position as returned by the Seek() and Skip() functions. + // Returns the current leaf edge for the desired seek or skip position and + // the offset of that position inside that edge. + struct Position { + CordRep* edge; + size_t offset; + }; + + // The read result as returned by the Read() function. + // `tree` contains the resulting tree which is identical to the result + // of calling CordRepBtree::SubTree(...) on the tree being navigated. + // `n` contains the number of bytes used from the last navigated to + // edge of the tree. + struct ReadResult { + CordRep* tree; + size_t n; + }; + + // Returns true if this instance is not empty. + explicit operator bool() const; + + // Returns the tree for this instance or nullptr if empty. + CordRepBtree* btree() const; + + // Returns the data edge of the current position. + // Requires this instance to not be empty. + CordRep* Current() const; + + // Resets this navigator to `tree`, returning the first data edge in the tree. + CordRep* InitFirst(CordRepBtree* tree); + + // Resets this navigator to `tree`, returning the last data edge in the tree. + CordRep* InitLast(CordRepBtree* tree); + + // Resets this navigator to `tree` returning the data edge at position + // `offset` and the relative offset of `offset` into that data edge. + // Returns `Position.edge = nullptr` if the provided offset is greater + // than or equal to the length of the tree, in which case the state of + // the navigator instance remains unchanged. + Position InitOffset(CordRepBtree* tree, size_t offset); + + // Navigates to the next data edge. + // Returns the next data edge or nullptr if there is no next data edge, in + // which case the current position remains unchanged. + CordRep* Next(); + + // Navigates to the previous data edge. + // Returns the previous data edge or nullptr if there is no previous data + // edge, in which case the current position remains unchanged. + CordRep* Previous(); + + // Navigates to the data edge at position `offset`. Returns the navigated to + // data edge in `Position.edge` and the relative offset of `offset` into that + // data edge in `Position.offset`. Returns `Position.edge = nullptr` if the + // provide offset is greater than or equal to the tree's length. + Position Seek(size_t offset); + + // Reads `n` bytes of data starting at offset `edge_offset` of the current + // data edge, and returns the result in `ReadResult.tree`. `ReadResult.n` + // contains the 'bytes used` from the last / current data edge in the tree. + // This allows users that mix regular navigation (using string views) and + // 'read into cord' navigation to keep track of the current state, and which + // bytes have been consumed from a navigator. + // This function returns `ReadResult.tree = nullptr` if the requested length + // exceeds the length of the tree starting at the current data edge. + ReadResult Read(size_t edge_offset, size_t n); + + // Skips `n` bytes forward from the current data edge, returning the navigated + // to data edge in `Position.edge` and `Position.offset` containing the offset + // inside that data edge. Note that the state of the navigator is left + // unchanged if `n` is smaller than the length of the current data edge. + Position Skip(size_t n); + + // Resets this instance to the default / empty state. + void Reset(); + + private: + // Slow path for Next() if Next() reached the end of a leaf node. Backtracks + // up the stack until it finds a node that has a 'next' position available, + // and then does a 'front dive' towards the next leaf node. + CordRep* NextUp(); + + // Slow path for Previous() if Previous() reached the beginning of a leaf + // node. Backtracks up the stack until it finds a node that has a 'previous' + // position available, and then does a 'back dive' towards the previous leaf + // node. + CordRep* PreviousUp(); + + // Generic implementation of InitFirst() and InitLast(). + template + CordRep* Init(CordRepBtree* tree); + + // `height_` contains the height of the current tree, or -1 if empty. + int height_ = -1; + + // `index_` and `node_` contain the navigation state as the 'path' to the + // current data edge which is at `node_[0]->Edge(index_[0])`. The contents + // of these are undefined until the instance is initialized (`height_ >= 0`). + uint8_t index_[CordRepBtree::kMaxHeight]; + CordRepBtree* node_[CordRepBtree::kMaxHeight]; +}; + +// Returns true if this instance is not empty. +inline CordRepBtreeNavigator::operator bool() const { return height_ >= 0; } + +inline CordRepBtree* CordRepBtreeNavigator::btree() const { + return height_ >= 0 ? node_[height_] : nullptr; +} + +inline CordRep* CordRepBtreeNavigator::Current() const { + assert(height_ >= 0); + return node_[0]->Edge(index_[0]); +} + +inline void CordRepBtreeNavigator::Reset() { height_ = -1; } + +inline CordRep* CordRepBtreeNavigator::InitFirst(CordRepBtree* tree) { + return Init(tree); +} + +inline CordRep* CordRepBtreeNavigator::InitLast(CordRepBtree* tree) { + return Init(tree); +} + +template +inline CordRep* CordRepBtreeNavigator::Init(CordRepBtree* tree) { + assert(tree != nullptr); + assert(tree->size() > 0); + int height = height_ = tree->height(); + size_t index = tree->index(edge_type); + node_[height] = tree; + index_[height] = static_cast(index); + while (--height >= 0) { + tree = tree->Edge(index)->btree(); + node_[height] = tree; + index = tree->index(edge_type); + index_[height] = static_cast(index); + } + return node_[0]->Edge(index); +} + +inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::Seek( + size_t offset) { + assert(btree() != nullptr); + int height = height_; + CordRepBtree* edge = node_[height]; + if (ABSL_PREDICT_FALSE(offset >= edge->length)) return {nullptr, 0}; + CordRepBtree::Position index = edge->IndexOf(offset); + index_[height] = static_cast(index.index); + while (--height >= 0) { + edge = edge->Edge(index.index)->btree(); + node_[height] = edge; + index = edge->IndexOf(index.n); + index_[height] = static_cast(index.index); + } + return {edge->Edge(index.index), index.n}; +} + +inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::InitOffset( + CordRepBtree* tree, size_t offset) { + assert(tree != nullptr); + if (ABSL_PREDICT_FALSE(offset >= tree->length)) return {nullptr, 0}; + height_ = tree->height(); + node_[height_] = tree; + return Seek(offset); +} + +inline CordRep* CordRepBtreeNavigator::Next() { + CordRepBtree* edge = node_[0]; + return index_[0] == edge->back() ? NextUp() : edge->Edge(++index_[0]); +} + +inline CordRep* CordRepBtreeNavigator::Previous() { + CordRepBtree* edge = node_[0]; + return index_[0] == edge->begin() ? PreviousUp() : edge->Edge(--index_[0]); +} + +inline CordRep* CordRepBtreeNavigator::NextUp() { + assert(index_[0] == node_[0]->back()); + CordRepBtree* edge; + size_t index; + int height = 0; + do { + if (++height > height_) return nullptr; + edge = node_[height]; + index = index_[height] + 1; + } while (index == edge->end()); + index_[height] = static_cast(index); + do { + node_[--height] = edge = edge->Edge(index)->btree(); + index_[height] = static_cast(index = edge->begin()); + } while (height > 0); + return edge->Edge(index); +} + +inline CordRep* CordRepBtreeNavigator::PreviousUp() { + assert(index_[0] == node_[0]->begin()); + CordRepBtree* edge; + size_t index; + int height = 0; + do { + if (++height > height_) return nullptr; + edge = node_[height]; + index = index_[height]; + } while (index == edge->begin()); + index_[height] = static_cast(--index); + do { + node_[--height] = edge = edge->Edge(index)->btree(); + index_[height] = static_cast(index = edge->back()); + } while (height > 0); + return edge->Edge(index); +} + +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_ diff --git a/absl/strings/internal/cord_rep_btree_navigator_test.cc b/absl/strings/internal/cord_rep_btree_navigator_test.cc new file mode 100644 index 00000000..ce09b199 --- /dev/null +++ b/absl/strings/internal/cord_rep_btree_navigator_test.cc @@ -0,0 +1,325 @@ +// Copyright 2021 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/strings/internal/cord_rep_btree_navigator.h" + +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/config.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cord_rep_btree.h" +#include "absl/strings/internal/cord_rep_test_util.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { +namespace { + +using ::testing::Eq; +using ::testing::Ne; + +using ::absl::cordrep_testing::CordRepBtreeFromFlats; +using ::absl::cordrep_testing::CordToString; +using ::absl::cordrep_testing::CreateFlatsFromString; +using ::absl::cordrep_testing::CreateRandomString; +using ::absl::cordrep_testing::MakeFlat; +using ::absl::cordrep_testing::MakeSubstring; + +using ReadResult = CordRepBtreeNavigator::ReadResult; +using Position = CordRepBtreeNavigator::Position; + +// CordRepBtreeNavigatorTest is a test fixture which automatically creates a +// tree to test navigation logic on. The parameter `count' defines the number of +// data edges in the test tree. +class CordRepBtreeNavigatorTest : public testing::TestWithParam { + public: + using Flats = std::vector; + static constexpr size_t kCharsPerFlat = 3; + + CordRepBtreeNavigatorTest() { + data_ = CreateRandomString(count() * kCharsPerFlat); + flats_ = CreateFlatsFromString(data_, kCharsPerFlat); + + // Turn flat 0 or 1 into a substring to cover partial reads on substrings. + if (count() > 1) { + CordRep::Unref(flats_[1]); + flats_[1] = MakeSubstring(kCharsPerFlat, kCharsPerFlat, MakeFlat(data_)); + } else { + CordRep::Unref(flats_[0]); + flats_[0] = MakeSubstring(0, kCharsPerFlat, MakeFlat(data_)); + } + + tree_ = CordRepBtreeFromFlats(flats_); + } + + ~CordRepBtreeNavigatorTest() override { CordRep::Unref(tree_); } + + int count() const { return GetParam(); } + CordRepBtree* tree() { return tree_; } + const std::string& data() const { return data_; } + const std::vector& flats() const { return flats_; } + + static std::string ToString(testing::TestParamInfo param) { + return absl::StrCat(param.param, "_Flats"); + } + + private: + std::string data_; + Flats flats_; + CordRepBtree* tree_; +}; + +INSTANTIATE_TEST_SUITE_P( + WithParam, CordRepBtreeNavigatorTest, + testing::Values(1, CordRepBtree::kMaxCapacity - 1, + CordRepBtree::kMaxCapacity, + CordRepBtree::kMaxCapacity* CordRepBtree::kMaxCapacity - 1, + CordRepBtree::kMaxCapacity* CordRepBtree::kMaxCapacity, + CordRepBtree::kMaxCapacity* CordRepBtree::kMaxCapacity + 1, + CordRepBtree::kMaxCapacity* CordRepBtree::kMaxCapacity * 2 + + 17), + CordRepBtreeNavigatorTest::ToString); + +TEST(CordRepBtreeNavigatorTest, Uninitialized) { + CordRepBtreeNavigator nav; + EXPECT_FALSE(nav); + EXPECT_THAT(nav.btree(), Eq(nullptr)); +#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) + EXPECT_DEATH(nav.Current(), ".*"); +#endif +} + +TEST_P(CordRepBtreeNavigatorTest, InitFirst) { + CordRepBtreeNavigator nav; + CordRep* edge = nav.InitFirst(tree()); + EXPECT_TRUE(nav); + EXPECT_THAT(nav.btree(), Eq(tree())); + EXPECT_THAT(nav.Current(), Eq(flats().front())); + EXPECT_THAT(edge, Eq(flats().front())); +} + +TEST_P(CordRepBtreeNavigatorTest, InitLast) { + CordRepBtreeNavigator nav; + CordRep* edge = nav.InitLast(tree()); + EXPECT_TRUE(nav); + EXPECT_THAT(nav.btree(), Eq(tree())); + EXPECT_THAT(nav.Current(), Eq(flats().back())); + EXPECT_THAT(edge, Eq(flats().back())); +} + +TEST_P(CordRepBtreeNavigatorTest, NextPrev) { + CordRepBtreeNavigator nav; + nav.InitFirst(tree()); + const Flats& flats = this->flats(); + + EXPECT_THAT(nav.Previous(), Eq(nullptr)); + EXPECT_THAT(nav.Current(), Eq(flats.front())); + for (int i = 1; i < flats.size(); ++i) { + ASSERT_THAT(nav.Next(), Eq(flats[i])); + EXPECT_THAT(nav.Current(), Eq(flats[i])); + } + EXPECT_THAT(nav.Next(), Eq(nullptr)); + EXPECT_THAT(nav.Current(), Eq(flats.back())); + for (int i = static_cast(flats.size()) - 2; i >= 0; --i) { + ASSERT_THAT(nav.Previous(), Eq(flats[i])); + EXPECT_THAT(nav.Current(), Eq(flats[i])); + } + EXPECT_THAT(nav.Previous(), Eq(nullptr)); + EXPECT_THAT(nav.Current(), Eq(flats.front())); +} + +TEST_P(CordRepBtreeNavigatorTest, PrevNext) { + CordRepBtreeNavigator nav; + nav.InitLast(tree()); + const Flats& flats = this->flats(); + + EXPECT_THAT(nav.Next(), Eq(nullptr)); + EXPECT_THAT(nav.Current(), Eq(flats.back())); + for (int i = static_cast(flats.size()) - 2; i >= 0; --i) { + ASSERT_THAT(nav.Previous(), Eq(flats[i])); + EXPECT_THAT(nav.Current(), Eq(flats[i])); + } + EXPECT_THAT(nav.Previous(), Eq(nullptr)); + EXPECT_THAT(nav.Current(), Eq(flats.front())); + for (int i = 1; i < flats.size(); ++i) { + ASSERT_THAT(nav.Next(), Eq(flats[i])); + EXPECT_THAT(nav.Current(), Eq(flats[i])); + } + EXPECT_THAT(nav.Next(), Eq(nullptr)); + EXPECT_THAT(nav.Current(), Eq(flats.back())); +} + +TEST(CordRepBtreeNavigatorTest, Reset) { + CordRepBtree* tree = CordRepBtree::Create(MakeFlat("abc")); + CordRepBtreeNavigator nav; + nav.InitFirst(tree); + nav.Reset(); + EXPECT_FALSE(nav); + EXPECT_THAT(nav.btree(), Eq(nullptr)); +#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) + EXPECT_DEATH(nav.Current(), ".*"); +#endif + CordRep::Unref(tree); +} + +TEST_P(CordRepBtreeNavigatorTest, Skip) { + int count = this->count(); + const Flats& flats = this->flats(); + CordRepBtreeNavigator nav; + nav.InitFirst(tree()); + + for (int char_offset = 0; char_offset < kCharsPerFlat; ++char_offset) { + Position pos = nav.Skip(char_offset); + EXPECT_THAT(pos.edge, Eq(nav.Current())); + EXPECT_THAT(pos.edge, Eq(flats[0])); + EXPECT_THAT(pos.offset, Eq(char_offset)); + } + + for (int index1 = 0; index1 < count; ++index1) { + for (int index2 = index1; index2 < count; ++index2) { + for (int char_offset = 0; char_offset < kCharsPerFlat; ++char_offset) { + CordRepBtreeNavigator nav; + nav.InitFirst(tree()); + + size_t length1 = index1 * kCharsPerFlat; + Position pos1 = nav.Skip(length1 + char_offset); + ASSERT_THAT(pos1.edge, Eq(flats[index1])); + ASSERT_THAT(pos1.edge, Eq(nav.Current())); + ASSERT_THAT(pos1.offset, Eq(char_offset)); + + size_t length2 = index2 * kCharsPerFlat; + Position pos2 = nav.Skip(length2 - length1 + char_offset); + ASSERT_THAT(pos2.edge, Eq(flats[index2])); + ASSERT_THAT(pos2.edge, Eq(nav.Current())); + ASSERT_THAT(pos2.offset, Eq(char_offset)); + } + } + } +} + +TEST_P(CordRepBtreeNavigatorTest, Seek) { + int count = this->count(); + const Flats& flats = this->flats(); + CordRepBtreeNavigator nav; + nav.InitFirst(tree()); + + for (int char_offset = 0; char_offset < kCharsPerFlat; ++char_offset) { + Position pos = nav.Seek(char_offset); + EXPECT_THAT(pos.edge, Eq(nav.Current())); + EXPECT_THAT(pos.edge, Eq(flats[0])); + EXPECT_THAT(pos.offset, Eq(char_offset)); + } + + for (int index = 0; index < count; ++index) { + for (int char_offset = 0; char_offset < kCharsPerFlat; ++char_offset) { + size_t offset = index * kCharsPerFlat + char_offset; + Position pos1 = nav.Seek(offset); + ASSERT_THAT(pos1.edge, Eq(flats[index])); + ASSERT_THAT(pos1.edge, Eq(nav.Current())); + ASSERT_THAT(pos1.offset, Eq(char_offset)); + } + } +} + +TEST(CordRepBtreeNavigatorTest, InitOffset) { + // Whitebox: InitOffset() is implemented in terms of Seek() which is + // exhaustively tested. Only test it initializes / forwards properly.. + CordRepBtree* tree = CordRepBtree::Create(MakeFlat("abc")); + tree = CordRepBtree::Append(tree, MakeFlat("def")); + CordRepBtreeNavigator nav; + Position pos = nav.InitOffset(tree, 5); + EXPECT_TRUE(nav); + EXPECT_THAT(nav.btree(), Eq(tree)); + EXPECT_THAT(pos.edge, Eq(tree->Edges()[1])); + EXPECT_THAT(pos.edge, Eq(nav.Current())); + EXPECT_THAT(pos.offset, Eq(2)); + CordRep::Unref(tree); +} + +TEST(CordRepBtreeNavigatorTest, InitOffsetAndSeekBeyondLength) { + CordRepBtree* tree1 = CordRepBtree::Create(MakeFlat("abc")); + CordRepBtree* tree2 = CordRepBtree::Create(MakeFlat("def")); + + CordRepBtreeNavigator nav; + nav.InitFirst(tree1); + EXPECT_THAT(nav.Seek(3).edge, Eq(nullptr)); + EXPECT_THAT(nav.Seek(100).edge, Eq(nullptr)); + EXPECT_THAT(nav.btree(), Eq(tree1)); + EXPECT_THAT(nav.Current(), Eq(tree1->Edges().front())); + + EXPECT_THAT(nav.InitOffset(tree2, 3).edge, Eq(nullptr)); + EXPECT_THAT(nav.InitOffset(tree2, 100).edge, Eq(nullptr)); + EXPECT_THAT(nav.btree(), Eq(tree1)); + EXPECT_THAT(nav.Current(), Eq(tree1->Edges().front())); + + CordRep::Unref(tree1); + CordRep::Unref(tree2); +} + +TEST_P(CordRepBtreeNavigatorTest, Read) { + const Flats& flats = this->flats(); + const std::string& data = this->data(); + + for (size_t offset = 0; offset < data.size(); ++offset) { + for (size_t length = 1; length <= data.size() - offset; ++length) { + CordRepBtreeNavigator nav; + nav.InitFirst(tree()); + + // Skip towards edge holding offset + size_t edge_offset = nav.Skip(offset).offset; + + // Read node + ReadResult result = nav.Read(edge_offset, length); + ASSERT_THAT(result.tree, Ne(nullptr)); + EXPECT_THAT(result.tree->length, Eq(length)); + if (result.tree->tag == BTREE) { + ASSERT_TRUE(CordRepBtree::IsValid(result.tree->btree())); + } + + // Verify contents + std::string value = CordToString(result.tree); + EXPECT_THAT(value, Eq(data.substr(offset, length))); + + // Verify 'partial last edge' reads. + size_t partial = (offset + length) % kCharsPerFlat; + ASSERT_THAT(result.n, Eq(partial)); + + // Verify ending position if not EOF + if (offset + length < data.size()) { + size_t index = (offset + length) / kCharsPerFlat; + EXPECT_THAT(nav.Current(), Eq(flats[index])); + } + + CordRep::Unref(result.tree); + } + } +} + +TEST_P(CordRepBtreeNavigatorTest, ReadBeyondLengthOfTree) { + CordRepBtreeNavigator nav; + nav.InitFirst(tree()); + ReadResult result = nav.Read(2, tree()->length); + ASSERT_THAT(result.tree, Eq(nullptr)); +} + +} // namespace +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index 968549be..ec6c431f 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h @@ -191,7 +191,9 @@ class string_view { ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // This is implemented in terms of `string_view(p, n)` so `str.size()` // doesn't need to be reevaluated after `ptr_` is set. - : string_view(str.data(), str.size()) {} + // The length check is also skipped since it is unnecessary and causes + // code bloat. + : string_view(str.data(), str.size(), SkipCheckLengthTag{}) {} // Implicit constructor of a `string_view` from NUL-terminated `str`. When // accepting possibly null strings, use `absl::NullSafeStringView(str)` @@ -594,6 +596,12 @@ class string_view { } private: + // The constructor from std::string delegates to this constuctor. + // See the comment on that constructor for the rationale. + struct SkipCheckLengthTag {}; + string_view(const char* data, size_type len, SkipCheckLengthTag) noexcept + : ptr_(data), length_(len) {} + static constexpr size_type kMaxSize = (std::numeric_limits::max)(); diff --git a/absl/time/time.h b/absl/time/time.h index 7fa0f5c6..e9cbce84 100644 --- a/absl/time/time.h +++ b/absl/time/time.h @@ -182,18 +182,29 @@ class Duration { // Overloads that forward to either the int64_t or double overloads above. // Integer operands must be representable as int64_t. - template + template = 0> Duration& operator*=(T r) { int64_t x = r; return *this *= x; } - template + + template = 0> Duration& operator/=(T r) { int64_t x = r; return *this /= x; } - Duration& operator*=(float r) { return *this *= static_cast(r); } - Duration& operator/=(float r) { return *this /= static_cast(r); } + + template = 0> + Duration& operator*=(T r) { + double x = r; + return *this *= x; + } + + template = 0> + Duration& operator/=(T r) { + double x = r; + return *this /= x; + } template friend H AbslHashValue(H h, Duration d) { @@ -392,12 +403,30 @@ constexpr Duration InfiniteDuration(); // // absl::Duration a = absl::Seconds(60); // absl::Duration b = absl::Minutes(1); // b == a -constexpr Duration Nanoseconds(int64_t n); -constexpr Duration Microseconds(int64_t n); -constexpr Duration Milliseconds(int64_t n); -constexpr Duration Seconds(int64_t n); -constexpr Duration Minutes(int64_t n); -constexpr Duration Hours(int64_t n); +template = 0> +constexpr Duration Nanoseconds(T n) { + return time_internal::FromInt64(n, std::nano{}); +} +template = 0> +constexpr Duration Microseconds(T n) { + return time_internal::FromInt64(n, std::micro{}); +} +template = 0> +constexpr Duration Milliseconds(T n) { + return time_internal::FromInt64(n, std::milli{}); +} +template = 0> +constexpr Duration Seconds(T n) { + return time_internal::FromInt64(n, std::ratio<1>{}); +} +template = 0> +constexpr Duration Minutes(T n) { + return time_internal::FromInt64(n, std::ratio<60>{}); +} +template = 0> +constexpr Duration Hours(T n) { + return time_internal::FromInt64(n, std::ratio<3600>{}); +} // Factory overloads for constructing `Duration` values from a floating-point // number of the unit indicated by the factory function's name. These functions @@ -1496,25 +1525,6 @@ T ToChronoDuration(Duration d) { } // namespace time_internal -constexpr Duration Nanoseconds(int64_t n) { - return time_internal::FromInt64(n, std::nano{}); -} -constexpr Duration Microseconds(int64_t n) { - return time_internal::FromInt64(n, std::micro{}); -} -constexpr Duration Milliseconds(int64_t n) { - return time_internal::FromInt64(n, std::milli{}); -} -constexpr Duration Seconds(int64_t n) { - return time_internal::FromInt64(n, std::ratio<1>{}); -} -constexpr Duration Minutes(int64_t n) { - return time_internal::FromInt64(n, std::ratio<60>{}); -} -constexpr Duration Hours(int64_t n) { - return time_internal::FromInt64(n, std::ratio<3600>{}); -} - constexpr bool operator<(Duration lhs, Duration rhs) { return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs) ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs) -- cgit v1.2.3 From 8910297baf87e1777c4fd30fb0693eecf9f2c134 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 13 Aug 2021 10:38:41 -0700 Subject: Export of internal Abseil changes -- 3a9b4e8e5ecba532db5cc4ac12d12660307ce9fb by Derek Mauro : Use the Bazel @platforms repository for platform constraints Fixes #1000 PiperOrigin-RevId: 390644226 -- b34e4d2f8a86b54bd483ec4c9c3dd781ad2d8b68 by Abseil Team : debugging: add some handling for RISC-V The RISC-V architecture uses a downward growing stack and can host Linux using ELF files. Adjust a few sites accordingly to indicate how to handle the RISC-V architecture. PiperOrigin-RevId: 390631894 -- 5fa3a0961bf3dd0799c048956a0128f7b8113f1e by Samuel Benzaquen : Rename the buffer hash function to LowLevelHash. Although it started as wyhash, it will depart from it so it does not make sense to keep the name. PiperOrigin-RevId: 390483506 -- 2e7867a2301d58ad4cd5abcaa5fd6f0db973ae7b by Abseil Team : This is an internal change. PiperOrigin-RevId: 390349746 GitOrigin-RevId: 3a9b4e8e5ecba532db5cc4ac12d12660307ce9fb Change-Id: I322c3762552a2107e6c6b108c25c01e5efa8aecd --- CMake/AbseilDll.cmake | 4 +- WORKSPACE | 8 + absl/BUILD.bazel | 4 +- absl/debugging/internal/stack_consumption.cc | 2 +- absl/debugging/internal/stack_consumption.h | 2 +- absl/debugging/internal/symbolize.h | 4 +- absl/hash/BUILD.bazel | 14 +- absl/hash/CMakeLists.txt | 14 +- absl/hash/internal/hash.cc | 13 +- absl/hash/internal/hash.h | 14 +- absl/hash/internal/low_level_hash.cc | 111 ++++++ absl/hash/internal/low_level_hash.h | 50 +++ absl/hash/internal/low_level_hash_test.cc | 486 +++++++++++++++++++++++++++ absl/hash/internal/wyhash.cc | 111 ------ absl/hash/internal/wyhash.h | 48 --- absl/hash/internal/wyhash_test.cc | 486 --------------------------- absl/time/internal/cctz/BUILD.bazel | 4 +- 17 files changed, 693 insertions(+), 682 deletions(-) create mode 100644 absl/hash/internal/low_level_hash.cc create mode 100644 absl/hash/internal/low_level_hash.h create mode 100644 absl/hash/internal/low_level_hash_test.cc delete mode 100644 absl/hash/internal/wyhash.cc delete mode 100644 absl/hash/internal/wyhash.h delete mode 100644 absl/hash/internal/wyhash_test.cc (limited to 'absl/debugging') diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 8bdf5a50..ea45c8a2 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -124,8 +124,8 @@ set(ABSL_INTERNAL_DLL_FILES "hash/internal/hash.h" "hash/internal/hash.cc" "hash/internal/spy_hash_state.h" - "hash/internal/wyhash.h" - "hash/internal/wyhash.cc" + "hash/internal/low_level_hash.h" + "hash/internal/low_level_hash.cc" "memory/memory.h" "meta/type_traits.h" "numeric/bits.h" diff --git a/WORKSPACE b/WORKSPACE index f4a5c476..af307872 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -42,3 +42,11 @@ http_archive( strip_prefix = "rules_cc-daf6ace7cfeacd6a83e9ff2ed659f416537b6c74", urls = ["https://github.com/bazelbuild/rules_cc/archive/daf6ace7cfeacd6a83e9ff2ed659f416537b6c74.zip"], ) + +# Bazel platform rules. +http_archive( + name = "platforms", + sha256 = "b601beaf841244de5c5a50d2b2eddd34839788000fa1be4260ce6603ca0d8eb7", + strip_prefix = "platforms-98939346da932eef0b54cf808622f5bb0928f00b", + urls = ["https://github.com/bazelbuild/platforms/archive/98939346da932eef0b54cf808622f5bb0928f00b.zip"], +) diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel index c9d4a2da..7239b5bf 100644 --- a/absl/BUILD.bazel +++ b/absl/BUILD.bazel @@ -44,14 +44,14 @@ config_setting( config_setting( name = "osx", constraint_values = [ - "@bazel_tools//platforms:osx", + "@platforms//os:osx", ], ) config_setting( name = "ios", constraint_values = [ - "@bazel_tools//platforms:ios", + "@platforms//os:ios", ], ) diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc index e3dd51c3..51348649 100644 --- a/absl/debugging/internal/stack_consumption.cc +++ b/absl/debugging/internal/stack_consumption.cc @@ -43,7 +43,7 @@ namespace { // unspecified. Therefore, instead we hardcode the direction of the // stack on platforms we know about. #if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \ - defined(__aarch64__) + defined(__aarch64__) || defined(__riscv) constexpr bool kStackGrowsDown = true; #else #error Need to define kStackGrowsDown diff --git a/absl/debugging/internal/stack_consumption.h b/absl/debugging/internal/stack_consumption.h index 2b5e7151..f41b64c3 100644 --- a/absl/debugging/internal/stack_consumption.h +++ b/absl/debugging/internal/stack_consumption.h @@ -26,7 +26,7 @@ #error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly #elif !defined(__APPLE__) && !defined(_WIN32) && \ (defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \ - defined(__aarch64__)) + defined(__aarch64__) || defined(__riscv)) #define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1 namespace absl { diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h index 8c296f89..27d5e652 100644 --- a/absl/debugging/internal/symbolize.h +++ b/absl/debugging/internal/symbolize.h @@ -28,8 +28,8 @@ #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE #error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set -#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \ - !defined(__asmjs__) && !defined(__wasm__) +#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) \ + && !defined(__asmjs__) && !defined(__wasm__) #define ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE 1 #include diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index 4b2c220f..21915cc1 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel @@ -37,7 +37,7 @@ cc_library( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":city", - ":wyhash", + ":low_level_hash", "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", @@ -143,9 +143,9 @@ cc_test( ) cc_library( - name = "wyhash", - srcs = ["internal/wyhash.cc"], - hdrs = ["internal/wyhash.h"], + name = "low_level_hash", + srcs = ["internal/low_level_hash.cc"], + hdrs = ["internal/low_level_hash.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], @@ -157,13 +157,13 @@ cc_library( ) cc_test( - name = "wyhash_test", - srcs = ["internal/wyhash_test.cc"], + name = "low_level_hash_test", + srcs = ["internal/low_level_hash_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ - ":wyhash", + ":low_level_hash", "//absl/strings", "@com_google_googletest//:gtest_main", ], diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index c82f66f0..6c79c93a 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt @@ -36,7 +36,7 @@ absl_cc_library( absl::optional absl::variant absl::utility - absl::wyhash + absl::low_level_hash PUBLIC ) @@ -118,11 +118,11 @@ absl_cc_test( absl_cc_library( NAME - wyhash + low_level_hash HDRS - "internal/wyhash.h" + "internal/low_level_hash.h" SRCS - "internal/wyhash.cc" + "internal/low_level_hash.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS @@ -133,13 +133,13 @@ absl_cc_library( absl_cc_test( NAME - wyhash_test + low_level_hash_test SRCS - "internal/wyhash_test.cc" + "internal/low_level_hash_test.cc" COPTS ${ABSL_TEST_COPTS} DEPS - absl::wyhash + absl::low_level_hash absl::strings GTest::gmock_main ) diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc index 06f53a59..4b818917 100644 --- a/absl/hash/internal/hash.cc +++ b/absl/hash/internal/hash.cc @@ -46,21 +46,22 @@ uint64_t MixingHashState::CombineLargeContiguousImpl64( ABSL_CONST_INIT const void* const MixingHashState::kSeed = &kSeed; -// The salt array used by Wyhash. This array is NOT the mechanism used to make -// absl::Hash non-deterministic between program invocations. See `Seed()` for -// that mechanism. +// The salt array used by LowLevelHash. This array is NOT the mechanism used to +// make absl::Hash non-deterministic between program invocations. See `Seed()` +// for that mechanism. // // Any random values are fine. These values are just digits from the decimal // part of pi. // https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number -constexpr uint64_t kWyhashSalt[5] = { +constexpr uint64_t kHashSalt[5] = { uint64_t{0x243F6A8885A308D3}, uint64_t{0x13198A2E03707344}, uint64_t{0xA4093822299F31D0}, uint64_t{0x082EFA98EC4E6C89}, uint64_t{0x452821E638D01377}, }; -uint64_t MixingHashState::WyhashImpl(const unsigned char* data, size_t len) { - return Wyhash(data, len, Seed(), kWyhashSalt); +uint64_t MixingHashState::LowLevelHashImpl(const unsigned char* data, + size_t len) { + return LowLevelHash(data, len, Seed(), kHashSalt); } } // namespace hash_internal diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index 90627e00..f5174096 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h @@ -42,7 +42,7 @@ #include "absl/base/internal/unaligned_access.h" #include "absl/base/port.h" #include "absl/container/fixed_array.h" -#include "absl/hash/internal/wyhash.h" +#include "absl/hash/internal/low_level_hash.h" #include "absl/meta/type_traits.h" #include "absl/numeric/int128.h" #include "absl/strings/string_view.h" @@ -874,14 +874,14 @@ class ABSL_DLL MixingHashState : public HashStateBase { return static_cast(m ^ (m >> (sizeof(m) * 8 / 2))); } - // An extern to avoid bloat on a direct call to Wyhash() with fixed values for - // both the seed and salt parameters. - static uint64_t WyhashImpl(const unsigned char* data, size_t len); + // An extern to avoid bloat on a direct call to LowLevelHash() with fixed + // values for both the seed and salt parameters. + static uint64_t LowLevelHashImpl(const unsigned char* data, size_t len); ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Hash64(const unsigned char* data, size_t len) { #ifdef ABSL_HAVE_INTRINSIC_INT128 - return WyhashImpl(data, len); + return LowLevelHashImpl(data, len); #else return absl::hash_internal::CityHash64(reinterpret_cast(data), len); #endif @@ -945,8 +945,8 @@ inline uint64_t MixingHashState::CombineContiguousImpl( inline uint64_t MixingHashState::CombineContiguousImpl( uint64_t state, const unsigned char* first, size_t len, std::integral_constant /* sizeof_size_t */) { - // For large values we use Wyhash or CityHash depending on the platform, for - // small ones we just use a multiplicative hash. + // For large values we use LowLevelHash or CityHash depending on the platform, + // for small ones we just use a multiplicative hash. uint64_t v; if (len > 16) { if (ABSL_PREDICT_FALSE(len > PiecewiseChunkSize())) { diff --git a/absl/hash/internal/low_level_hash.cc b/absl/hash/internal/low_level_hash.cc new file mode 100644 index 00000000..856bbd9b --- /dev/null +++ b/absl/hash/internal/low_level_hash.cc @@ -0,0 +1,111 @@ +// Copyright 2020 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/hash/internal/low_level_hash.h" + +#include "absl/base/internal/unaligned_access.h" +#include "absl/numeric/int128.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace hash_internal { + +static uint64_t Mix(uint64_t v0, uint64_t v1) { + absl::uint128 p = v0; + p *= v1; + return absl::Uint128Low64(p) ^ absl::Uint128High64(p); +} + +uint64_t LowLevelHash(const void* data, size_t len, uint64_t seed, + const uint64_t salt[]) { + const uint8_t* ptr = static_cast(data); + uint64_t starting_length = static_cast(len); + uint64_t current_state = seed ^ salt[0]; + + if (len > 64) { + // If we have more than 64 bytes, we're going to handle chunks of 64 + // bytes at a time. We're going to build up two separate hash states + // which we will then hash together. + uint64_t duplicated_state = current_state; + + do { + uint64_t a = absl::base_internal::UnalignedLoad64(ptr); + uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8); + uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16); + uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24); + uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32); + uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40); + uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48); + uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56); + + uint64_t cs0 = Mix(a ^ salt[1], b ^ current_state); + uint64_t cs1 = Mix(c ^ salt[2], d ^ current_state); + current_state = (cs0 ^ cs1); + + uint64_t ds0 = Mix(e ^ salt[3], f ^ duplicated_state); + uint64_t ds1 = Mix(g ^ salt[4], h ^ duplicated_state); + duplicated_state = (ds0 ^ ds1); + + ptr += 64; + len -= 64; + } while (len > 64); + + current_state = current_state ^ duplicated_state; + } + + // We now have a data `ptr` with at most 64 bytes and the current state + // of the hashing state machine stored in current_state. + while (len > 16) { + uint64_t a = absl::base_internal::UnalignedLoad64(ptr); + uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8); + + current_state = Mix(a ^ salt[1], b ^ current_state); + + ptr += 16; + len -= 16; + } + + // We now have a data `ptr` with at most 16 bytes. + uint64_t a = 0; + uint64_t b = 0; + if (len > 8) { + // When we have at least 9 and at most 16 bytes, set A to the first 64 + // bits of the input and B to the last 64 bits of the input. Yes, they will + // overlap in the middle if we are working with less than the full 16 + // bytes. + a = absl::base_internal::UnalignedLoad64(ptr); + b = absl::base_internal::UnalignedLoad64(ptr + len - 8); + } else if (len > 3) { + // If we have at least 4 and at most 8 bytes, set A to the first 32 + // bits and B to the last 32 bits. + a = absl::base_internal::UnalignedLoad32(ptr); + b = absl::base_internal::UnalignedLoad32(ptr + len - 4); + } else if (len > 0) { + // If we have at least 1 and at most 3 bytes, read all of the provided + // bits into A, with some adjustments. + a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); + b = 0; + } else { + a = 0; + b = 0; + } + + uint64_t w = Mix(a ^ salt[1], b ^ current_state); + uint64_t z = salt[1] ^ starting_length; + return Mix(w, z); +} + +} // namespace hash_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/hash/internal/low_level_hash.h b/absl/hash/internal/low_level_hash.h new file mode 100644 index 00000000..439968aa --- /dev/null +++ b/absl/hash/internal/low_level_hash.h @@ -0,0 +1,50 @@ +// Copyright 2020 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file provides the Google-internal implementation of LowLevelHash. +// +// LowLevelHash is a fast hash function for hash tables, the fastest we've +// currently (late 2020) found that passes the SMHasher tests. The algorithm +// relies on intrinsic 128-bit multiplication for speed. This is not meant to be +// secure - just fast. +// +// It is closely based on a version of wyhash, but does not maintain or +// guarantee future compatibility with it. + +#ifndef ABSL_HASH_INTERNAL_LOW_LEVEL_HASH_H_ +#define ABSL_HASH_INTERNAL_LOW_LEVEL_HASH_H_ + +#include +#include + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace hash_internal { + +// Hash function for a byte array. A 64-bit seed and a set of five 64-bit +// integers are hashed into the result. +// +// To allow all hashable types (including string_view and Span) to depend on +// this algorithm, we keep the API low-level, with as few dependencies as +// possible. +uint64_t LowLevelHash(const void* data, size_t len, uint64_t seed, + const uint64_t salt[5]); + +} // namespace hash_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_HASH_INTERNAL_LOW_LEVEL_HASH_H_ diff --git a/absl/hash/internal/low_level_hash_test.cc b/absl/hash/internal/low_level_hash_test.cc new file mode 100644 index 00000000..0ef50236 --- /dev/null +++ b/absl/hash/internal/low_level_hash_test.cc @@ -0,0 +1,486 @@ +// Copyright 2020 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/hash/internal/low_level_hash.h" + +#include "absl/strings/escaping.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace { + +static const uint64_t kCurrentSeed = 0; +static const uint64_t kSalt[5] = {0xa0761d6478bd642f, 0xe7037ed1a0b428dbl, + 0x8ebc6af09c88c6e3, 0x589965cc75374cc3l, + 0x1d8e4e27c47d124f}; + +// Note: We don't account for endianness, so the values here are only correct if +// you're also running on a little endian platform. + +TEST(LowLevelHashTest, EmptyString) { + const std::string s = ""; + EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), + kCurrentSeed, kSalt), + 4808886099364463827); +} + +TEST(LowLevelHashTest, Spaces) { + const std::string s = " "; + EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), + kCurrentSeed, kSalt), + 1686201463024549249); +} + +TEST(LowLevelHashTest, RepeatingString) { + const std::string s = "aaaa"; + EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), + kCurrentSeed, kSalt), + 6646112255271966632); +} + +TEST(LowLevelHashTest, HexString) { + const std::string small = "\x01\x02\x03"; + const std::string med = "\x01\x02\x03\x04"; + + EXPECT_EQ(absl::hash_internal::LowLevelHash(small.c_str(), small.length(), + kCurrentSeed, kSalt), + 11989428023081740911ULL); + EXPECT_EQ(absl::hash_internal::LowLevelHash(med.c_str(), med.length(), + kCurrentSeed, kSalt), + 9765997711188871556ULL); +} + +TEST(LowLevelHashTest, Words) { + const std::string s = "third_party|wyhash|64"; + EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), + kCurrentSeed, kSalt), + 3702018632387611330); +} + +TEST(LowLevelHashTest, LongString) { + const std::string s = + "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz" + "0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOp" + "QrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEf" + "GhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz012345" + "6789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789"; + + EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), + kCurrentSeed, kSalt), + 9245411362605796064ULL); +} + +TEST(LowLevelHashTest, BigReference) { + struct ExpectedResult { + absl::string_view base64_data; + uint64_t seed; + uint64_t hash; + } expected_results[] = { + {"", uint64_t{0xec42b7ab404b8acb}, uint64_t{0xe5a40d39ab796423}}, + {"Zw==", uint64_t{0xeeee074043a3ee0f}, uint64_t{0xa6564b468248c683}}, + {"xmk=", uint64_t{0x857902089c393de}, uint64_t{0xef192f401b116e1c}}, + {"c1H/", uint64_t{0x993df040024ca3af}, uint64_t{0xbe8dc0c54617639d}}, + {"SuwpzQ==", uint64_t{0xc4e4c2acea740e96}, uint64_t{0x93d7f665b5521c8e}}, + {"uqvy++M=", uint64_t{0x6a214b3db872d0cf}, uint64_t{0x646d70bb42445f28}}, + {"RnzCVPgb", uint64_t{0x44343db6a89dba4d}, uint64_t{0x96a7b1e3cc9bd426}}, + {"6OeNdlouYw==", uint64_t{0x77b5d6d1ae1dd483}, + uint64_t{0x76020289ab0790c4}}, + {"M5/JmmYyDbc=", uint64_t{0x89ab8ecb44d221f1}, + uint64_t{0x39f842e4133b9b44}}, + {"MVijWiVdBRdY", uint64_t{0x60244b17577ca81b}, + uint64_t{0x2b8d7047be4bcaab}}, + {"6V7Uq7LNxpu0VA==", uint64_t{0x59a08dcee0717067}, + uint64_t{0x99628abef6716a97}}, + {"EQ6CdEEhPdyHcOk=", uint64_t{0xf5f20db3ade57396}, + uint64_t{0x4432e02ba42b2740}}, + {"PqFB4fxnPgF+l+rc", uint64_t{0xbf8dee0751ad3efb}, + uint64_t{0x74d810efcad7918a}}, + {"a5aPOFwq7LA7+zKvPA==", uint64_t{0x6b7a06b268d63e30}, + uint64_t{0x88c84e986002507f}}, + {"VOwY21wCGv5D+/qqOvs=", uint64_t{0xb8c37f0ae0f54c82}, + uint64_t{0x4f99acf193cf39b9}}, + {"KdHmBTx8lHXYvmGJ+Vy7", uint64_t{0x9fcbed0c38e50eef}, + uint64_t{0xd90e7a3655891e37}}, + {"qJkPlbHr8bMF7/cA6aE65Q==", uint64_t{0x2af4bade1d8e3a1d}, + uint64_t{0x3bb378b1d4df8fcf}}, + {"ygvL0EhHZL0fIx6oHHtkxRQ=", uint64_t{0x714e3aa912da2f2c}, + uint64_t{0xf78e94045c052d47}}, + {"c1rFXkt5YztwZCQRngncqtSs", uint64_t{0xf5ee75e3cbb82c1c}, + uint64_t{0x26da0b2130da6b40}}, + {"8hsQrzszzeNQSEcVXLtvIhm6mw==", uint64_t{0x620e7007321b93b9}, + uint64_t{0x30b4d426af8c6986}}, + {"ffUL4RocfyP4KfikGxO1yk7omDI=", uint64_t{0xc08528cac2e551fc}, + uint64_t{0x5413b4aaf3baaeae}}, + {"OOB5TT00vF9Od/rLbAWshiErqhpV", uint64_t{0x6a1debf9cc3ad39}, + uint64_t{0x756ab265370a1597}}, + {"or5wtXM7BFzTNpSzr+Lw5J5PMhVJ/Q==", uint64_t{0x7e0a3c88111fc226}, + uint64_t{0xdaf5f4b7d09814fb}}, + {"gk6pCHDUsoopVEiaCrzVDhioRKxb844=", uint64_t{0x1301fef15df39edb}, + uint64_t{0x8f874ae37742b75e}}, + {"TNctmwlC5QbEM6/No4R/La3UdkfeMhzs", uint64_t{0x64e181f3d5817ab}, + uint64_t{0x8fecd03956121ce8}}, + {"SsQw9iAjhWz7sgcE9OwLuSC6hsM+BfHs2Q==", uint64_t{0xafafc44961078ecb}, + uint64_t{0x229c292ea7a08285}}, + {"ZzO3mVCj4xTT2TT3XqDyEKj2BZQBvrS8RHg=", uint64_t{0x4f7bb45549250094}, + uint64_t{0xbb4bf0692d14bae}}, + {"+klp5iPQGtppan5MflEls0iEUzqU+zGZkDJX", uint64_t{0xa30061abaa2818c}, + uint64_t{0x207b24ca3bdac1db}}, + {"RO6bvOnlJc8I9eniXlNgqtKy0IX6VNg16NRmgg==", uint64_t{0xd902ee3e44a5705f}, + uint64_t{0x64f6cd6745d3825b}}, + {"ZJjZqId1ZXBaij9igClE3nyliU5XWdNRrayGlYA=", uint64_t{0x316d36da516f583}, + uint64_t{0xa2b2e1656b58df1e}}, + {"7BfkhfGMDGbxfMB8uyL85GbaYQtjr2K8g7RpLzr/", uint64_t{0x402d83f9f834f616}, + uint64_t{0xd01d30d9ee7a148}}, + {"rycWk6wHH7htETQtje9PidS2YzXBx+Qkg2fY7ZYS7A==", + uint64_t{0x9c604164c016b72c}, uint64_t{0x1cb4cd00ab804e3b}}, + {"RTkC2OUK+J13CdGllsH0H5WqgspsSa6QzRZouqx6pvI=", + uint64_t{0x3f4507e01f9e73ba}, uint64_t{0x4697f2637fd90999}}, + {"tKjKmbLCNyrLCM9hycOAXm4DKNpM12oZ7dLTmUx5iwAi", + uint64_t{0xc3fe0d5be8d2c7c7}, uint64_t{0x8383a756b5688c07}}, + {"VprUGNH+5NnNRaORxgH/ySrZFQFDL+4VAodhfBNinmn8cg==", + uint64_t{0x531858a40bfa7ea1}, uint64_t{0x695c29cb3696a975}}, + {"gc1xZaY+q0nPcUvOOnWnT3bqfmT/geth/f7Dm2e/DemMfk4=", + uint64_t{0x86689478a7a7e8fa}, uint64_t{0xda2e5a5a5e971521}}, + {"Mr35fIxqx1ukPAL0su1yFuzzAU3wABCLZ8+ZUFsXn47UmAph", + uint64_t{0x4ec948b8e7f27288}, uint64_t{0x7935d4befa056b2b}}, + {"A9G8pw2+m7+rDtWYAdbl8tb2fT7FFo4hLi2vAsa5Y8mKH3CX3g==", + uint64_t{0xce46c7213c10032}, uint64_t{0x38dd541ca95420fe}}, + {"DFaJGishGwEHDdj9ixbCoaTjz9KS0phLNWHVVdFsM93CvPft3hM=", + uint64_t{0xf63e96ee6f32a8b6}, uint64_t{0xcc06c7a4963f967f}}, + {"7+Ugx+Kr3aRNgYgcUxru62YkTDt5Hqis+2po81hGBkcrJg4N0uuy", + uint64_t{0x1cfe85e65fc5225}, uint64_t{0xbf0f6f66e232fb20}}, + {"H2w6O8BUKqu6Tvj2xxaecxEI2wRgIgqnTTG1WwOgDSINR13Nm4d4Vg==", + uint64_t{0x45c474f1cee1d2e8}, uint64_t{0xf7efb32d373fe71a}}, + {"1XBMnIbqD5jy65xTDaf6WtiwtdtQwv1dCVoqpeKj+7cTR1SaMWMyI04=", + uint64_t{0x6e024e14015f329c}, uint64_t{0xe2e64634b1c12660}}, + {"znZbdXG2TSFrKHEuJc83gPncYpzXGbAebUpP0XxzH0rpe8BaMQ17nDbt", + uint64_t{0x760c40502103ae1c}, uint64_t{0x285b8fd1638e306d}}, + {"ylu8Atu13j1StlcC1MRMJJXIl7USgDDS22HgVv0WQ8hx/8pNtaiKB17hCQ==", + uint64_t{0x17fd05c3c560c320}, uint64_t{0x658e8a4e3b714d6c}}, + {"M6ZVVzsd7vAvbiACSYHioH/440dp4xG2mLlBnxgiqEvI/aIEGpD0Sf4VS0g=", + uint64_t{0x8b34200a6f8e90d9}, uint64_t{0xf391fb968e0eb398}}, + {"li3oFSXLXI+ubUVGJ4blP6mNinGKLHWkvGruun85AhVn6iuMtocbZPVhqxzn", + uint64_t{0x6be89e50818bdf69}, uint64_t{0x744a9ea0cc144bf2}}, + {"kFuQHuUCqBF3Tc3hO4dgdIp223ShaCoog48d5Do5zMqUXOh5XpGK1t5XtxnfGA==", + uint64_t{0xfb389773315b47d8}, uint64_t{0x12636f2be11012f1}}, + {"jWmOad0v0QhXVJd1OdGuBZtDYYS8wBVHlvOeTQx9ZZnm8wLEItPMeihj72E0nWY=", + uint64_t{0x4f2512a23f61efee}, uint64_t{0x29c57de825948f80}}, + {"z+DHU52HaOQdW4JrZwDQAebEA6rm13Zg/9lPYA3txt3NjTBqFZlOMvTRnVzRbl23", + uint64_t{0x59ccd92fc16c6fda}, uint64_t{0x58c6f99ab0d1c021}}, + {"MmBiGDfYeTayyJa/tVycg+rN7f9mPDFaDc+23j0TlW9094er0ADigsl4QX7V3gG/qw==", + uint64_t{0x25c5a7f5bd330919}, uint64_t{0x13e7b5a7b82fe3bb}}, + {"774RK+9rOL4iFvs1q2qpo/JVc/I39buvNjqEFDtDvyoB0FXxPI2vXqOrk08VPfIHkmU=", + uint64_t{0x51df4174d34c97d7}, uint64_t{0x10fbc87901e02b63}}, + {"+slatXiQ7/2lK0BkVUI1qzNxOOLP3I1iK6OfHaoxgqT63FpzbElwEXSwdsryq3UlHK0I", + uint64_t{0x80ce6d76f89cb57}, uint64_t{0xa24c9184901b748b}}, + {"64mVTbQ47dHjHlOHGS/hjJwr/" + "K2frCNpn87exOqMzNUVYiPKmhCbfS7vBUce5tO6Ec9osQ==", + uint64_t{0x20961c911965f684}, uint64_t{0xcac4fd4c5080e581}}, + {"fIsaG1r530SFrBqaDj1kqE0AJnvvK8MNEZbII2Yw1OK77v0V59xabIh0B5axaz/" + "+a2V5WpA=", + uint64_t{0x4e5b926ec83868e7}, uint64_t{0xc38bdb7483ba68e1}}, + {"PGih0zDEOWCYGxuHGDFu9Ivbff/" + "iE7BNUq65tycTR2R76TerrXALRosnzaNYO5fjFhTi+CiS", + uint64_t{0x3927b30b922eecef}, uint64_t{0xdb2a8069b2ceaffa}}, + {"RnpA/" + "zJnEnnLjmICORByRVb9bCOgxF44p3VMiW10G7PvW7IhwsWajlP9kIwNA9FjAD2GoQHk2Q=" + "=", + uint64_t{0xbd0291284a49b61c}, uint64_t{0xdf9fe91d0d1c7887}}, + {"qFklMceaTHqJpy2qavJE+EVBiNFOi6OxjOA3LeIcBop1K7w8xQi3TrDk+" + "BrWPRIbfprszSaPfrI=", + uint64_t{0x73a77c575bcc956}, uint64_t{0xe83f49e96e2e6a08}}, + {"cLbfUtLl3EcQmITWoTskUR8da/VafRDYF/ylPYwk7/" + "zazk6ssyrzxMN3mmSyvrXR2yDGNZ3WDrTT", + uint64_t{0x766a0e2ade6d09a6}, uint64_t{0xc69e61b62ca2b62}}, + {"s/" + "Jf1+" + "FbsbCpXWPTUSeWyMH6e4CvTFvPE5Fs6Z8hvFITGyr0dtukHzkI84oviVLxhM1xMxrMAy1db" + "w==", + uint64_t{0x2599f4f905115869}, uint64_t{0xb4a4f3f85f8298fe}}, + {"FvyQ00+j7nmYZVQ8hI1Edxd0AWplhTfWuFGiu34AK5X8u2hLX1bE97sZM0CmeLe+" + "7LgoUT1fJ/axybE=", + uint64_t{0xd8256e5444d21e53}, uint64_t{0x167a1b39e1e95f41}}, + {"L8ncxMaYLBH3g9buPu8hfpWZNlOF7nvWLNv9IozH07uQsIBWSKxoPy8+" + "LW4tTuzC6CIWbRGRRD1sQV/4", + uint64_t{0xf664a91333fb8dfd}, uint64_t{0xf8a2a5649855ee41}}, + {"CDK0meI07yrgV2kQlZZ+" + "wuVqhc2NmzqeLH7bmcA6kchsRWFPeVF5Wqjjaj556ABeUoUr3yBmfU3kWOakkg==", + uint64_t{0x9625b859be372cd1}, uint64_t{0x27992565b595c498}}, + {"d23/vc5ONh/" + "HkMiq+gYk4gaCNYyuFKwUkvn46t+dfVcKfBTYykr4kdvAPNXGYLjM4u1YkAEFpJP+" + "nX7eOvs=", + uint64_t{0x7b99940782e29898}, uint64_t{0x3e08cca5b71f9346}}, + {"NUR3SRxBkxTSbtQORJpu/GdR6b/h6sSGfsMj/KFd99ahbh+9r7LSgSGmkGVB/" + "mGoT0pnMTQst7Lv2q6QN6Vm", + uint64_t{0x4fe12fa5383b51a8}, uint64_t{0xad406b10c770a6d2}}, + {"2BOFlcI3Z0RYDtS9T9Ie9yJoXlOdigpPeeT+CRujb/" + "O39Ih5LPC9hP6RQk1kYESGyaLZZi3jtabHs7DiVx/VDg==", + uint64_t{0xe2ccb09ac0f5b4b6}, uint64_t{0xd1713ce6e552bcf2}}, + {"FF2HQE1FxEvWBpg6Z9zAMH+Zlqx8S1JD/" + "wIlViL6ZDZY63alMDrxB0GJQahmAtjlm26RGLnjW7jmgQ4Ie3I+014=", + uint64_t{0x7d0a37adbd7b753b}, uint64_t{0x753b287194c73ad3}}, + {"tHmO7mqVL/PX11nZrz50Hc+M17Poj5lpnqHkEN+4bpMx/" + "YGbkrGOaYjoQjgmt1X2QyypK7xClFrjeWrCMdlVYtbW", + uint64_t{0xd3ae96ef9f7185f2}, uint64_t{0x5ae41a95f600af1c}}, + {"/WiHi9IQcxRImsudkA/KOTqGe8/" + "gXkhKIHkjddv5S9hi02M049dIK3EUyAEjkjpdGLUs+BN0QzPtZqjIYPOgwsYE9g==", + uint64_t{0x4fb88ea63f79a0d8}, uint64_t{0x4a61163b86a8bb4c}}, + {"qds+1ExSnU11L4fTSDz/QE90g4Jh6ioqSh3KDOTOAo2pQGL1k/" + "9CCC7J23YF27dUTzrWsCQA2m4epXoCc3yPHb3xElA=", + uint64_t{0xed564e259bb5ebe9}, uint64_t{0x42eeaa79e760c7e4}}, + {"8FVYHx40lSQPTHheh08Oq0/" + "pGm2OlG8BEf8ezvAxHuGGdgCkqpXIueJBF2mQJhTfDy5NncO8ntS7vaKs7sCNdDaNGOEi", + uint64_t{0x3e3256b60c428000}, uint64_t{0x698df622ef465b0a}}, + {"4ZoEIrJtstiCkeew3oRzmyJHVt/pAs2pj0HgHFrBPztbQ10NsQ/" + "lM6DM439QVxpznnBSiHMgMQJhER+70l72LqFTO1JiIQ==", + uint64_t{0xfb05bad59ec8705}, uint64_t{0x157583111e1a6026}}, + {"hQPtaYI+wJyxXgwD5n8jGIKFKaFA/" + "P83KqCKZfPthnjwdOFysqEOYwAaZuaaiv4cDyi9TyS8hk5cEbNP/jrI7q6pYGBLbsM=", + uint64_t{0xafdc251dbf97b5f8}, uint64_t{0xaa1388f078e793e0}}, + {"S4gpMSKzMD7CWPsSfLeYyhSpfWOntyuVZdX1xSBjiGvsspwOZcxNKCRIOqAA0moUfOh3I5+" + "juQV4rsqYElMD/gWfDGpsWZKQ", + uint64_t{0x10ec9c92ddb5dcbc}, uint64_t{0xf10d68d0f3309360}}, + {"oswxop+" + "bthuDLT4j0PcoSKby4LhF47ZKg8K17xxHf74UsGCzTBbOz0MM8hQEGlyqDT1iUiAYnaPaUp" + "L2mRK0rcIUYA4qLt5uOw==", + uint64_t{0x9a767d5822c7dac4}, uint64_t{0x2af056184457a3de}}, + {"0II/" + "697p+" + "BtLSjxj5989OXI004TogEb94VUnDzOVSgMXie72cuYRvTFNIBgtXlKfkiUjeqVpd4a+" + "n5bxNOD1TGrjQtzKU5r7obo=", + uint64_t{0xee46254080d6e2db}, uint64_t{0x6d0058e1590b2489}}, + {"E84YZW2qipAlMPmctrg7TKlwLZ68l4L+c0xRDUfyyFrA4MAti0q9sHq3TDFviH0Y+" + "Kq3tEE5srWFA8LM9oomtmvm5PYxoaarWPLc", + uint64_t{0xbbb669588d8bf398}, uint64_t{0x638f287f68817f12}}, + {"x3pa4HIElyZG0Nj7Vdy9IdJIR4izLmypXw5PCmZB5y68QQ4uRaVVi3UthsoJROvbjDJkP2D" + "Q6L/eN8pFeLFzNPKBYzcmuMOb5Ull7w==", + uint64_t{0xdc2afaa529beef44}, uint64_t{0xc46b71fecefd5467}}, + {"jVDKGYIuWOP/" + "QKLdd2wi8B2VJA8Wh0c8PwrXJVM8FOGM3voPDVPyDJOU6QsBDPseoR8uuKd19OZ/" + "zAvSCB+zlf6upAsBlheUKgCfKww=", + uint64_t{0xf1f67391d45013a8}, uint64_t{0x2c8e94679d964e0a}}, + {"mkquunhmYe1aR2wmUz4vcvLEcKBoe6H+kjUok9VUn2+eTSkWs4oDDtJvNCWtY5efJwg/" + "j4PgjRYWtqnrCkhaqJaEvkkOwVfgMIwF3e+d", + uint64_t{0x16fce2b8c65a3429}, uint64_t{0x8612b797ce22503a}}, + {"fRelvKYonTQ+s+rnnvQw+JzGfFoPixtna0vzcSjiDqX5s2Kg2//" + "UGrK+AVCyMUhO98WoB1DDbrsOYSw2QzrcPe0+3ck9sePvb+Q/IRaHbw==", + uint64_t{0xf4b096699f49fe67}, uint64_t{0x59f929babfba7170}}, + {"DUwXFJzagljo44QeJ7/" + "6ZKw4QXV18lhkYT2jglMr8WB3CHUU4vdsytvw6AKv42ZcG6fRkZkq9fpnmXy6xG0aO3WPT1" + "eHuyFirAlkW+zKtwg=", + uint64_t{0xca584c4bc8198682}, uint64_t{0x9527556923fb49a0}}, + {"cYmZCrOOBBongNTr7e4nYn52uQUy2mfe48s50JXx2AZ6cRAt/" + "xRHJ5QbEoEJOeOHsJyM4nbzwFm++SlT6gFZZHJpkXJ92JkR86uS/eV1hJUR", + uint64_t{0xed269fc3818b6aad}, uint64_t{0x1039ab644f5e150b}}, + {"EXeHBDfhwzAKFhsMcH9+2RHwV+mJaN01+9oacF6vgm8mCXRd6jeN9U2oAb0of5c5cO4i+" + "Vb/LlHZSMI490SnHU0bejhSCC2gsC5d2K30ER3iNA==", + uint64_t{0x33f253cbb8fe66a8}, uint64_t{0x7816c83f3aa05e6d}}, + {"FzkzRYoNjkxFhZDso94IHRZaJUP61nFYrh5MwDwv9FNoJ5jyNCY/" + "eazPZk+tbmzDyJIGw2h3GxaWZ9bSlsol/vK98SbkMKCQ/wbfrXRLcDzdd/8=", + uint64_t{0xd0b76b2c1523d99c}, uint64_t{0xf51d2f564518c619}}, + {"Re4aXISCMlYY/XsX7zkIFR04ta03u4zkL9dVbLXMa/q6hlY/CImVIIYRN3VKP4pnd0AUr/" + "ugkyt36JcstAInb4h9rpAGQ7GMVOgBniiMBZ/MGU7H", + uint64_t{0xfd28f0811a2a237f}, uint64_t{0x67d494cff03ac004}}, + {"ueLyMcqJXX+MhO4UApylCN9WlTQ+" + "ltJmItgG7vFUtqs2qNwBMjmAvr5u0sAKd8jpzV0dDPTwchbIeAW5zbtkA2NABJV6hFM48ib" + "4/J3A5mseA3cS8w==", + uint64_t{0x6261fb136482e84}, uint64_t{0x2802d636ced1cfbb}}, + {"6Si7Yi11L+jZMkwaN+GUuzXMrlvEqviEkGOilNq0h8TdQyYKuFXzkYc/" + "q74gP3pVCyiwz9KpVGMM9vfnq36riMHRknkmhQutxLZs5fbmOgEO69HglCU=", + uint64_t{0x458efc750bca7c3a}, uint64_t{0xf64e20bad771cb12}}, + {"Q6AbOofGuTJOegPh9Clm/" + "9crtUMQqylKrTc1fhfJo1tqvpXxhU4k08kntL1RG7woRnFrVh2UoMrL1kjin+s9CanT+" + "y4hHwLqRranl9FjvxfVKm3yvg68", + uint64_t{0xa7e69ff84e5e7c27}, uint64_t{0xb9a6cf84a83e15e}}, + {"ieQEbIPvqY2YfIjHnqfJiO1/MIVRk0RoaG/WWi3kFrfIGiNLCczYoklgaecHMm/" + "1sZ96AjO+a5stQfZbJQwS7Sc1ODABEdJKcTsxeW2hbh9A6CFzpowP1A==", + uint64_t{0x3c59bfd0c29efe9e}, uint64_t{0x8da6630319609301}}, + {"zQUv8hFB3zh2GGl3KTvCmnfzE+" + "SUgQPVaSVIELFX5H9cE3FuVFGmymkPQZJLAyzC90Cmi8GqYCvPqTuAAB//" + "XTJxy4bCcVArgZG9zJXpjowpNBfr3ngWrSE=", + uint64_t{0x10befacc6afd298d}, uint64_t{0x40946a86e2a996f3}}, + {"US4hcC1+op5JKGC7eIs8CUgInjKWKlvKQkapulxW262E/" + "B2ye79QxOexf188u2mFwwe3WTISJHRZzS61IwljqAWAWoBAqkUnW8SHmIDwHUP31J0p5sGd" + "P47L", + uint64_t{0x41d5320b0a38efa7}, uint64_t{0xcab7f5997953fa76}}, + {"9bHUWFna2LNaGF6fQLlkx1Hkt24nrkLE2CmFdWgTQV3FFbUe747SSqYw6ebpTa07MWSpWRP" + "sHesVo2B9tqHbe7eQmqYebPDFnNqrhSdZwFm9arLQVs+7a3Ic6A==", + uint64_t{0x58db1c7450fe17f3}, uint64_t{0x39129ca0e04fc465}}, + {"Kb3DpHRUPhtyqgs3RuXjzA08jGb59hjKTOeFt1qhoINfYyfTt2buKhD6YVffRCPsgK9SeqZ" + "qRPJSyaqsa0ovyq1WnWW8jI/NhvAkZTVHUrX2pC+cD3OPYT05Dag=", + uint64_t{0x6098c055a335b7a6}, uint64_t{0x5238221fd685e1b8}}, + {"gzxyMJIPlU+bJBwhFUCHSofZ/" + "319LxqMoqnt3+L6h2U2+ZXJCSsYpE80xmR0Ta77Jq54o92SMH87HV8dGOaCTuAYF+" + "lDL42SY1P316Cl0sZTS2ow3ZqwGbcPNs/1", + uint64_t{0x1bbacec67845a801}, uint64_t{0x175130c407dbcaab}}, + {"uR7V0TW+FGVMpsifnaBAQ3IGlr1wx5sKd7TChuqRe6OvUXTlD4hKWy8S+" + "8yyOw8lQabism19vOQxfmocEOW/" + "vzY0pEa87qHrAZy4s9fH2Bltu8vaOIe+agYohhYORQ==", + uint64_t{0xc419cfc7442190}, uint64_t{0x2f20e7536c0b0df}}, + {"1UR5eoo2aCwhacjZHaCh9bkOsITp6QunUxHQ2SfeHv0imHetzt/" + "Z70mhyWZBalv6eAx+YfWKCUib2SHDtz/" + "A2dc3hqUWX5VfAV7FQsghPUAtu6IiRatq4YSLpDvKZBQ=", + uint64_t{0xc95e510d94ba270c}, uint64_t{0x2742cb488a04ad56}}, + {"opubR7H63BH7OtY+Avd7QyQ25UZ8kLBdFDsBTwZlY6gA/" + "u+x+" + "czC9AaZMgmQrUy15DH7YMGsvdXnviTtI4eVI4aF1H9Rl3NXMKZgwFOsdTfdcZeeHVRzBBKX" + "8jUfh1il", + uint64_t{0xff1ae05c98089c3f}, uint64_t{0xd6afb593879ff93b}}, + {"DC0kXcSXtfQ9FbSRwirIn5tgPri0sbzHSa78aDZVDUKCMaBGyFU6BmrulywYX8yzvwprdLs" + "oOwTWN2wMjHlPDqrvVHNEjnmufRDblW+nSS+xtKNs3N5xsxXdv6JXDrAB/Q==", + uint64_t{0x90c02b8dceced493}, uint64_t{0xf50ad64caac0ca7f}}, + {"BXRBk+3wEP3Lpm1y75wjoz+PgB0AMzLe8tQ1AYU2/" + "oqrQB2YMC6W+9QDbcOfkGbeH+b7IBkt/" + "gwCMw2HaQsRFEsurXtcQ3YwRuPz5XNaw5NAvrNa67Fm7eRzdE1+hWLKtA8=", + uint64_t{0x9f8a76697ab1aa36}, uint64_t{0x2ade95c4261364ae}}, + {"RRBSvEGYnzR9E45Aps/+WSnpCo/X7gJLO4DRnUqFrJCV/kzWlusLE/" + "6ZU6RoUf2ROwcgEvUiXTGjLs7ts3t9SXnJHxC1KiOzxHdYLMhVvgNd3hVSAXODpKFSkVXND" + "55G2L1W", + uint64_t{0x6ba1bf3d811a531d}, uint64_t{0x5c4f3299faacd07a}}, + {"jeh6Qazxmdi57pa9S3XSnnZFIRrnc6s8QLrah5OX3SB/V2ErSPoEAumavzQPkdKF1/" + "SfvmdL+qgF1C+Yawy562QaFqwVGq7+tW0yxP8FStb56ZRgNI4IOmI30s1Ei7iops9Uuw==", + uint64_t{0x6a418974109c67b4}, uint64_t{0xfffe3bff0ae5e9bc}}, + {"6QO5nnDrY2/" + "wrUXpltlKy2dSBcmK15fOY092CR7KxAjNfaY+" + "aAmtWbbzQk3MjBg03x39afSUN1fkrWACdyQKRaGxgwq6MGNxI6W+8DLWJBHzIXrntrE/" + "ml6fnNXEpxplWJ1vEs4=", + uint64_t{0x8472f1c2b3d230a3}, uint64_t{0x1db785c0005166e4}}, + {"0oPxeEHhqhcFuwonNfLd5jF3RNATGZS6NPoS0WklnzyokbTqcl4BeBkMn07+fDQv83j/" + "BpGUwcWO05f3+DYzocfnizpFjLJemFGsls3gxcBYxcbqWYev51tG3lN9EvRE+X9+Pwww", + uint64_t{0x5e06068f884e73a7}, uint64_t{0xea000d962ad18418}}, + {"naSBSjtOKgAOg8XVbR5cHAW3Y+QL4Pb/JO9/" + "oy6L08wvVRZqo0BrssMwhzBP401Um7A4ppAupbQeJFdMrysY34AuSSNvtNUy5VxjNECwiNt" + "gwYHw7yakDUv8WvonctmnoSPKENegQg==", + uint64_t{0x55290b1a8f170f59}, uint64_t{0xe42aef38359362d9}}, + {"vPyl8DxVeRe1OpilKb9KNwpGkQRtA94UpAHetNh+" + "95V7nIW38v7PpzhnTWIml5kw3So1Si0TXtIUPIbsu32BNhoH7QwFvLM+" + "JACgSpc5e3RjsL6Qwxxi11npwxRmRUqATDeMUfRAjxg=", + uint64_t{0x5501cfd83dfe706a}, uint64_t{0xc8e95657348a3891}}, + {"QC9i2GjdTMuNC1xQJ74ngKfrlA4w3o58FhvNCltdIpuMhHP1YsDA78scQPLbZ3OCUgeQguY" + "f/vw6zAaVKSgwtaykqg5ka/4vhz4hYqWU5ficdXqClHl+zkWEY26slCNYOM5nnDlly8Cj", + uint64_t{0xe43ed13d13a66990}, uint64_t{0xc162eca864f238c6}}, + {"7CNIgQhAHX27nxI0HeB5oUTnTdgKpRDYDKwRcXfSFGP1XeT9nQF6WKCMjL1tBV6x7KuJ91G" + "Zz11F4c+8s+MfqEAEpd4FHzamrMNjGcjCyrVtU6y+7HscMVzr7Q/" + "ODLcPEFztFnwjvCjmHw==", + uint64_t{0xdf43bc375cf5283f}, uint64_t{0xbe1fb373e20579ad}}, + {"Qa/hC2RPXhANSospe+gUaPfjdK/yhQvfm4cCV6/pdvCYWPv8p1kMtKOX3h5/" + "8oZ31fsmx4Axphu5qXJokuhZKkBUJueuMpxRyXpwSWz2wELx5glxF7CM0Fn+" + "OevnkhUn5jsPlG2r5jYlVn8=", + uint64_t{0x8112b806d288d7b5}, uint64_t{0x628a1d4f40aa6ffd}}, + {"kUw/0z4l3a89jTwN5jpG0SHY5km/" + "IVhTjgM5xCiPRLncg40aqWrJ5vcF891AOq5hEpSq0bUCJUMFXgct7kvnys905HjerV7Vs1G" + "y84tgVJ70/2+pAZTsB/PzNOE/G6sOj4+GbTzkQu819OLB", + uint64_t{0xd52a18abb001cb46}, uint64_t{0xa87bdb7456340f90}}, + {"VDdfSDbO8Tdj3T5W0XM3EI7iHh5xpIutiM6dvcJ/fhe23V/srFEkDy5iZf/" + "VnA9kfi2C79ENnFnbOReeuZW1b3MUXB9lgC6U4pOTuC+" + "jHK3Qnpyiqzj7h3ISJSuo2pob7vY6VHZo6Fn7exEqHg==", + uint64_t{0xe12b76a2433a1236}, uint64_t{0x5960ef3ba982c801}}, + {"Ldfvy3ORdquM/R2fIkhH/ONi69mcP1AEJ6n/" + "oropwecAsLJzQSgezSY8bEiEs0VnFTBBsW+RtZY6tDj03fnb3amNUOq1b7jbqyQkL9hpl+" + "2Z2J8IaVSeownWl+bQcsR5/xRktIMckC5AtF4YHfU=", + uint64_t{0x175bf7319cf1fa00}, uint64_t{0x5026586df9a431ec}}, + {"BrbNpb42+" + "VzZAjJw6QLirXzhweCVRfwlczzZ0VX2xluskwBqyfnGovz5EuX79JJ31VNXa5hTkAyQat3l" + "YKRADTdAdwE5PqM1N7YaMqqsqoAAAeuYVXuk5eWCykYmClNdSspegwgCuT+403JigBzi", + uint64_t{0xd63d57b3f67525ae}, uint64_t{0xfe4b8a20fdf0840b}}, + {"gB3NGHJJvVcuPyF0ZSvHwnWSIfmaI7La24VMPQVoIIWF7Z74NltPZZpx2f+cocESM+" + "ILzQW9p+BC8x5IWz7N4Str2WLGKMdgmaBfNkEhSHQDU0IJEOnpUt0HmjhFaBlx0/" + "LTmhua+rQ6Wup8ezLwfg==", + uint64_t{0x933faea858832b73}, uint64_t{0xdcb761867da7072f}}, + {"hTKHlRxx6Pl4gjG+6ksvvj0CWFicUg3WrPdSJypDpq91LUWRni2KF6+" + "81ZoHBFhEBrCdogKqeK+hy9bLDnx7g6rAFUjtn1+cWzQ2YjiOpz4+" + "ROBB7lnwjyTGWzJD1rXtlso1g2qVH8XJVigC5M9AIxM=", + uint64_t{0x53d061e5f8e7c04f}, uint64_t{0xc10d4653667275b7}}, + {"IWQBelSQnhrr0F3BhUpXUIDauhX6f95Qp+A0diFXiUK7irwPG1oqBiqHyK/SH/" + "9S+" + "rln9DlFROAmeFdH0OCJi2tFm4afxYzJTFR4HnR4cG4x12JqHaZLQx6iiu6CE3rtWBVz99oA" + "wCZUOEXIsLU24o2Y", + uint64_t{0xdb4124556dd515e0}, uint64_t{0x727720deec13110b}}, + {"TKo+l+" + "1dOXdLvIrFqeLaHdm0HZnbcdEgOoLVcGRiCbAMR0j5pIFw8D36tefckAS1RCFOH5IgP8yiF" + "T0Gd0a2hI3+" + "fTKA7iK96NekxWeoeqzJyctc6QsoiyBlkZerRxs5RplrxoeNg29kKDTM0K94mnhD9g==", + uint64_t{0x4fb31a0dd681ee71}, uint64_t{0x710b009662858dc9}}, + {"YU4e7G6EfQYvxCFoCrrT0EFgVLHFfOWRTJQJ5gxM3G2b+" + "1kJf9YPrpsxF6Xr6nYtS8reEEbDoZJYqnlk9lXSkVArm88Cqn6d25VCx3+" + "49MqC0trIlXtb7SXUUhwpJK16T0hJUfPH7s5cMZXc6YmmbFuBNPE=", + uint64_t{0x27cc72eefa138e4c}, uint64_t{0xfbf8f7a3ecac1eb7}}, + {"/I/" + "eImMwPo1U6wekNFD1Jxjk9XQVi1D+" + "FPdqcHifYXQuP5aScNQfxMAmaPR2XhuOQhADV5tTVbBKwCDCX4E3jcDNHzCiPvViZF1W27t" + "xaf2BbFQdwKrNCmrtzcluBFYu0XZfc7RU1RmxK/RtnF1qHsq/O4pp", + uint64_t{0x44bc2dfba4bd3ced}, uint64_t{0xb6fc4fcd0722e3df}}, + {"CJTT9WGcY2XykTdo8KodRIA29qsqY0iHzWZRjKHb9alwyJ7RZAE3V5Juv4MY3MeYEr1EPCC" + "MxO7yFXqT8XA8YTjaMp3bafRt17Pw8JC4iKJ1zN+WWKOESrj+" + "3aluGQqn8z1EzqY4PH7rLG575PYeWsP98BugdA==", + uint64_t{0x242da1e3a439bed8}, uint64_t{0x7cb86dcc55104aac}}, + {"ZlhyQwLhXQyIUEnMH/" + "AEW27vh9xrbNKJxpWGtrEmKhd+nFqAfbeNBQjW0SfG1YI0xQkQMHXjuTt4P/" + "EpZRtA47ibZDVS8TtaxwyBjuIDwqcN09eCtpC+Ls+" + "vWDTLmBeDM3u4hmzz4DQAYsLiZYSJcldg9Q3wszw=", + uint64_t{0xdc559c746e35c139}, uint64_t{0x19e71e9b45c3a51e}}, + {"v2KU8y0sCrBghmnm8lzGJlwo6D6ObccAxCf10heoDtYLosk4ztTpLlpSFEyu23MLA1tJkcg" + "Rko04h19QMG0mOw/" + "wc93EXAweriBqXfvdaP85sZABwiKO+6rtS9pacRVpYYhHJeVTQ5NzrvBvi1huxAr+" + "xswhVMfL", + uint64_t{0xd0b0350275b9989}, uint64_t{0x51de38573c2bea48}}, + {"QhKlnIS6BuVCTQsnoE67E/" + "yrgogE8EwO7xLaEGei26m0gEU4OksefJgppDh3X0x0Cs78Dr9IHK5b977CmZlrTRmwhlP8p" + "M+UzXPNRNIZuN3ntOum/QhUWP8SGpirheXENWsXMQ/" + "nxtxakyEtrNkKk471Oov9juP8oQ==", + uint64_t{0xb04489e41d17730c}, uint64_t{0xa73ab6996d6df158}}, + {"/ZRMgnoRt+Uo6fUPr9FqQvKX7syhgVqWu+" + "WUSsiQ68UlN0efSP6Eced5gJZL6tg9gcYJIkhjuQNITU0Q3TjVAnAcobgbJikCn6qZ6pRxK" + "BY4MTiAlfGD3T7R7hwJwx554MAy++Zb/YUFlnCaCJiwQMnowF7aQzwYFCo=", + uint64_t{0x2217285eb4572156}, uint64_t{0x55ef2b8c930817b2}}, + {"NB7tU5fNE8nI+SXGfipc7sRkhnSkUF1krjeo6k+8FITaAtdyz+" + "o7mONgXmGLulBPH9bEwyYhKNVY0L+njNQrZ9YC2aXsFD3PdZsxAFaBT3VXEzh+" + "NGBTjDASNL3mXyS8Yv1iThGfHoY7T4aR0NYGJ+k+pR6f+KrPC96M", + uint64_t{0x12c2e8e68aede73b}, uint64_t{0xb2850bf5fae87157}}, + {"8T6wrqCtEO6/rwxF6lvMeyuigVOLwPipX/FULvwyu+1wa5sQGav/" + "2FsLHUVn6cGSi0LlFwLewGHPFJDLR0u4t7ZUyM//" + "x6da0sWgOa5hzDqjsVGmjxEHXiaXKW3i4iSZNuxoNbMQkIbVML+" + "DkYu9ND0O2swg4itGeVSzXA==", + uint64_t{0x4d612125bdc4fd00}, uint64_t{0xecf3de1acd04651f}}, + {"Ntf1bMRdondtMv1CYr3G80iDJ4WSAlKy5H34XdGruQiCrnRGDBa+" + "eUi7vKp4gp3BBcVGl8eYSasVQQjn7MLvb3BjtXx6c/" + "bCL7JtpzQKaDnPr9GWRxpBXVxKREgMM7d8lm35EODv0w+" + "hQLfVSh8OGs7fsBb68nNWPLeeSOo=", + uint64_t{0x81826b553954464e}, uint64_t{0xcc0a40552559ff32}}, + {"VsSAw72Ro6xks02kaiLuiTEIWBC5bgqr4WDnmP8vglXzAhixk7td926rm9jNimL+" + "kroPSygZ9gl63aF5DCPOACXmsbmhDrAQuUzoh9ZKhWgElLQsrqo1KIjWoZT5b5QfVUXY9lS" + "IBg3U75SqORoTPq7HalxxoIT5diWOcJQi", + uint64_t{0xc2e5d345dc0ddd2d}, uint64_t{0xc385c374f20315b1}}, + {"j+loZ+C87+" + "bJxNVebg94gU0mSLeDulcHs84tQT7BZM2rzDSLiCNxUedHr1ZWJ9ejTiBa0dqy2I2ABc++" + "xzOLcv+//YfibtjKtYggC6/3rv0XCc7xu6d/" + "O6xO+XOBhOWAQ+IHJVHf7wZnDxIXB8AUHsnjEISKj7823biqXjyP3g==", + uint64_t{0x3da6830a9e32631e}, uint64_t{0xb90208a4c7234183}}, + {"f3LlpcPElMkspNtDq5xXyWU62erEaKn7RWKlo540gR6mZsNpK1czV/" + "sOmqaq8XAQLEn68LKj6/" + "cFkJukxRzCa4OF1a7cCAXYFp9+wZDu0bw4y63qbpjhdCl8GO6Z2lkcXy7KOzbPE01ukg7+" + "gN+7uKpoohgAhIwpAKQXmX5xtd0=", + uint64_t{0xc9ae5c8759b4877a}, uint64_t{0x58aa1ca7a4c075d9}}, + }; + + for (const auto& expected_result : expected_results) { + std::string str; + ASSERT_TRUE(absl::Base64Unescape(expected_result.base64_data, &str)); + EXPECT_EQ(absl::hash_internal::LowLevelHash(str.data(), str.size(), + expected_result.seed, kSalt), + expected_result.hash); + } +} + +} // namespace diff --git a/absl/hash/internal/wyhash.cc b/absl/hash/internal/wyhash.cc deleted file mode 100644 index 642bde43..00000000 --- a/absl/hash/internal/wyhash.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2020 The Abseil Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/hash/internal/wyhash.h" - -#include "absl/base/internal/unaligned_access.h" -#include "absl/numeric/int128.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace hash_internal { - -static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { - absl::uint128 p = v0; - p *= v1; - return absl::Uint128Low64(p) ^ absl::Uint128High64(p); -} - -uint64_t Wyhash(const void* data, size_t len, uint64_t seed, - const uint64_t salt[]) { - const uint8_t* ptr = static_cast(data); - uint64_t starting_length = static_cast(len); - uint64_t current_state = seed ^ salt[0]; - - if (len > 64) { - // If we have more than 64 bytes, we're going to handle chunks of 64 - // bytes at a time. We're going to build up two separate hash states - // which we will then hash together. - uint64_t duplicated_state = current_state; - - do { - uint64_t a = absl::base_internal::UnalignedLoad64(ptr); - uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8); - uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16); - uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24); - uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32); - uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40); - uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48); - uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56); - - uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); - current_state = (cs0 ^ cs1); - - uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); - uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); - duplicated_state = (ds0 ^ ds1); - - ptr += 64; - len -= 64; - } while (len > 64); - - current_state = current_state ^ duplicated_state; - } - - // We now have a data `ptr` with at most 64 bytes and the current state - // of the hashing state machine stored in current_state. - while (len > 16) { - uint64_t a = absl::base_internal::UnalignedLoad64(ptr); - uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8); - - current_state = WyhashMix(a ^ salt[1], b ^ current_state); - - ptr += 16; - len -= 16; - } - - // We now have a data `ptr` with at most 16 bytes. - uint64_t a = 0; - uint64_t b = 0; - if (len > 8) { - // When we have at least 9 and at most 16 bytes, set A to the first 64 - // bits of the input and B to the last 64 bits of the input. Yes, they will - // overlap in the middle if we are working with less than the full 16 - // bytes. - a = absl::base_internal::UnalignedLoad64(ptr); - b = absl::base_internal::UnalignedLoad64(ptr + len - 8); - } else if (len > 3) { - // If we have at least 4 and at most 8 bytes, set A to the first 32 - // bits and B to the last 32 bits. - a = absl::base_internal::UnalignedLoad32(ptr); - b = absl::base_internal::UnalignedLoad32(ptr + len - 4); - } else if (len > 0) { - // If we have at least 1 and at most 3 bytes, read all of the provided - // bits into A, with some adjustments. - a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); - b = 0; - } else { - a = 0; - b = 0; - } - - uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t z = salt[1] ^ starting_length; - return WyhashMix(w, z); -} - -} // namespace hash_internal -ABSL_NAMESPACE_END -} // namespace absl diff --git a/absl/hash/internal/wyhash.h b/absl/hash/internal/wyhash.h deleted file mode 100644 index 2b534b47..00000000 --- a/absl/hash/internal/wyhash.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2020 The Abseil Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file provides the Google-internal implementation of the Wyhash -// algorithm. -// -// Wyhash is a fast hash function for hash tables, the fastest we've currently -// (late 2020) found that passes the SMHasher tests. The algorithm relies on -// intrinsic 128-bit multiplication for speed. This is not meant to be secure - -// just fast. - -#ifndef ABSL_HASH_INTERNAL_WYHASH_H_ -#define ABSL_HASH_INTERNAL_WYHASH_H_ - -#include -#include - -#include "absl/base/config.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace hash_internal { - -// Hash function for a byte array. A 64-bit seed and a set of five 64-bit -// integers are hashed into the result. -// -// To allow all hashable types (including string_view and Span) to depend on -// this algorithm, we keep the API low-level, with as few dependencies as -// possible. -uint64_t Wyhash(const void* data, size_t len, uint64_t seed, - const uint64_t salt[5]); - -} // namespace hash_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_HASH_INTERNAL_WYHASH_H_ diff --git a/absl/hash/internal/wyhash_test.cc b/absl/hash/internal/wyhash_test.cc deleted file mode 100644 index 9fb06d23..00000000 --- a/absl/hash/internal/wyhash_test.cc +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright 2020 The Abseil Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/hash/internal/wyhash.h" - -#include "absl/strings/escaping.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace { - -static const uint64_t kCurrentSeed = 0; -static const uint64_t kSalt[5] = {0xa0761d6478bd642f, 0xe7037ed1a0b428dbl, - 0x8ebc6af09c88c6e3, 0x589965cc75374cc3l, - 0x1d8e4e27c47d124f}; - -// Note: We don't account for endianness, so the values here are only correct if -// you're also running on a little endian platform. - -TEST(WyhashTest, EmptyString) { - const std::string s = ""; - EXPECT_EQ( - absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt), - 4808886099364463827); -} - -TEST(WyhashTest, Spaces) { - const std::string s = " "; - EXPECT_EQ( - absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt), - 1686201463024549249); -} - -TEST(WyhashTest, RepeatingString) { - const std::string s = "aaaa"; - EXPECT_EQ( - absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt), - 6646112255271966632); -} - -TEST(WyhashTest, HexString) { - const std::string small = "\x01\x02\x03"; - const std::string med = "\x01\x02\x03\x04"; - - EXPECT_EQ(absl::hash_internal::Wyhash(small.c_str(), small.length(), - kCurrentSeed, kSalt), - 11989428023081740911ULL); - EXPECT_EQ(absl::hash_internal::Wyhash(med.c_str(), med.length(), kCurrentSeed, - kSalt), - 9765997711188871556ULL); -} - -TEST(WyhashTest, Words) { - const std::string s = "third_party|wyhash|64"; - EXPECT_EQ( - absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt), - 3702018632387611330); -} - -TEST(WyhashTest, LongString) { - const std::string s = - "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz" - "0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOp" - "QrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEf" - "GhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz012345" - "6789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789"; - - EXPECT_EQ( - absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt), - 9245411362605796064ULL); -} - -TEST(WyhashTest, BigReference) { - struct ExpectedResult { - absl::string_view base64_data; - uint64_t seed; - uint64_t hash; - } expected_results[] = { - {"", uint64_t{0xec42b7ab404b8acb}, uint64_t{0xe5a40d39ab796423}}, - {"Zw==", uint64_t{0xeeee074043a3ee0f}, uint64_t{0xa6564b468248c683}}, - {"xmk=", uint64_t{0x857902089c393de}, uint64_t{0xef192f401b116e1c}}, - {"c1H/", uint64_t{0x993df040024ca3af}, uint64_t{0xbe8dc0c54617639d}}, - {"SuwpzQ==", uint64_t{0xc4e4c2acea740e96}, uint64_t{0x93d7f665b5521c8e}}, - {"uqvy++M=", uint64_t{0x6a214b3db872d0cf}, uint64_t{0x646d70bb42445f28}}, - {"RnzCVPgb", uint64_t{0x44343db6a89dba4d}, uint64_t{0x96a7b1e3cc9bd426}}, - {"6OeNdlouYw==", uint64_t{0x77b5d6d1ae1dd483}, - uint64_t{0x76020289ab0790c4}}, - {"M5/JmmYyDbc=", uint64_t{0x89ab8ecb44d221f1}, - uint64_t{0x39f842e4133b9b44}}, - {"MVijWiVdBRdY", uint64_t{0x60244b17577ca81b}, - uint64_t{0x2b8d7047be4bcaab}}, - {"6V7Uq7LNxpu0VA==", uint64_t{0x59a08dcee0717067}, - uint64_t{0x99628abef6716a97}}, - {"EQ6CdEEhPdyHcOk=", uint64_t{0xf5f20db3ade57396}, - uint64_t{0x4432e02ba42b2740}}, - {"PqFB4fxnPgF+l+rc", uint64_t{0xbf8dee0751ad3efb}, - uint64_t{0x74d810efcad7918a}}, - {"a5aPOFwq7LA7+zKvPA==", uint64_t{0x6b7a06b268d63e30}, - uint64_t{0x88c84e986002507f}}, - {"VOwY21wCGv5D+/qqOvs=", uint64_t{0xb8c37f0ae0f54c82}, - uint64_t{0x4f99acf193cf39b9}}, - {"KdHmBTx8lHXYvmGJ+Vy7", uint64_t{0x9fcbed0c38e50eef}, - uint64_t{0xd90e7a3655891e37}}, - {"qJkPlbHr8bMF7/cA6aE65Q==", uint64_t{0x2af4bade1d8e3a1d}, - uint64_t{0x3bb378b1d4df8fcf}}, - {"ygvL0EhHZL0fIx6oHHtkxRQ=", uint64_t{0x714e3aa912da2f2c}, - uint64_t{0xf78e94045c052d47}}, - {"c1rFXkt5YztwZCQRngncqtSs", uint64_t{0xf5ee75e3cbb82c1c}, - uint64_t{0x26da0b2130da6b40}}, - {"8hsQrzszzeNQSEcVXLtvIhm6mw==", uint64_t{0x620e7007321b93b9}, - uint64_t{0x30b4d426af8c6986}}, - {"ffUL4RocfyP4KfikGxO1yk7omDI=", uint64_t{0xc08528cac2e551fc}, - uint64_t{0x5413b4aaf3baaeae}}, - {"OOB5TT00vF9Od/rLbAWshiErqhpV", uint64_t{0x6a1debf9cc3ad39}, - uint64_t{0x756ab265370a1597}}, - {"or5wtXM7BFzTNpSzr+Lw5J5PMhVJ/Q==", uint64_t{0x7e0a3c88111fc226}, - uint64_t{0xdaf5f4b7d09814fb}}, - {"gk6pCHDUsoopVEiaCrzVDhioRKxb844=", uint64_t{0x1301fef15df39edb}, - uint64_t{0x8f874ae37742b75e}}, - {"TNctmwlC5QbEM6/No4R/La3UdkfeMhzs", uint64_t{0x64e181f3d5817ab}, - uint64_t{0x8fecd03956121ce8}}, - {"SsQw9iAjhWz7sgcE9OwLuSC6hsM+BfHs2Q==", uint64_t{0xafafc44961078ecb}, - uint64_t{0x229c292ea7a08285}}, - {"ZzO3mVCj4xTT2TT3XqDyEKj2BZQBvrS8RHg=", uint64_t{0x4f7bb45549250094}, - uint64_t{0xbb4bf0692d14bae}}, - {"+klp5iPQGtppan5MflEls0iEUzqU+zGZkDJX", uint64_t{0xa30061abaa2818c}, - uint64_t{0x207b24ca3bdac1db}}, - {"RO6bvOnlJc8I9eniXlNgqtKy0IX6VNg16NRmgg==", uint64_t{0xd902ee3e44a5705f}, - uint64_t{0x64f6cd6745d3825b}}, - {"ZJjZqId1ZXBaij9igClE3nyliU5XWdNRrayGlYA=", uint64_t{0x316d36da516f583}, - uint64_t{0xa2b2e1656b58df1e}}, - {"7BfkhfGMDGbxfMB8uyL85GbaYQtjr2K8g7RpLzr/", uint64_t{0x402d83f9f834f616}, - uint64_t{0xd01d30d9ee7a148}}, - {"rycWk6wHH7htETQtje9PidS2YzXBx+Qkg2fY7ZYS7A==", - uint64_t{0x9c604164c016b72c}, uint64_t{0x1cb4cd00ab804e3b}}, - {"RTkC2OUK+J13CdGllsH0H5WqgspsSa6QzRZouqx6pvI=", - uint64_t{0x3f4507e01f9e73ba}, uint64_t{0x4697f2637fd90999}}, - {"tKjKmbLCNyrLCM9hycOAXm4DKNpM12oZ7dLTmUx5iwAi", - uint64_t{0xc3fe0d5be8d2c7c7}, uint64_t{0x8383a756b5688c07}}, - {"VprUGNH+5NnNRaORxgH/ySrZFQFDL+4VAodhfBNinmn8cg==", - uint64_t{0x531858a40bfa7ea1}, uint64_t{0x695c29cb3696a975}}, - {"gc1xZaY+q0nPcUvOOnWnT3bqfmT/geth/f7Dm2e/DemMfk4=", - uint64_t{0x86689478a7a7e8fa}, uint64_t{0xda2e5a5a5e971521}}, - {"Mr35fIxqx1ukPAL0su1yFuzzAU3wABCLZ8+ZUFsXn47UmAph", - uint64_t{0x4ec948b8e7f27288}, uint64_t{0x7935d4befa056b2b}}, - {"A9G8pw2+m7+rDtWYAdbl8tb2fT7FFo4hLi2vAsa5Y8mKH3CX3g==", - uint64_t{0xce46c7213c10032}, uint64_t{0x38dd541ca95420fe}}, - {"DFaJGishGwEHDdj9ixbCoaTjz9KS0phLNWHVVdFsM93CvPft3hM=", - uint64_t{0xf63e96ee6f32a8b6}, uint64_t{0xcc06c7a4963f967f}}, - {"7+Ugx+Kr3aRNgYgcUxru62YkTDt5Hqis+2po81hGBkcrJg4N0uuy", - uint64_t{0x1cfe85e65fc5225}, uint64_t{0xbf0f6f66e232fb20}}, - {"H2w6O8BUKqu6Tvj2xxaecxEI2wRgIgqnTTG1WwOgDSINR13Nm4d4Vg==", - uint64_t{0x45c474f1cee1d2e8}, uint64_t{0xf7efb32d373fe71a}}, - {"1XBMnIbqD5jy65xTDaf6WtiwtdtQwv1dCVoqpeKj+7cTR1SaMWMyI04=", - uint64_t{0x6e024e14015f329c}, uint64_t{0xe2e64634b1c12660}}, - {"znZbdXG2TSFrKHEuJc83gPncYpzXGbAebUpP0XxzH0rpe8BaMQ17nDbt", - uint64_t{0x760c40502103ae1c}, uint64_t{0x285b8fd1638e306d}}, - {"ylu8Atu13j1StlcC1MRMJJXIl7USgDDS22HgVv0WQ8hx/8pNtaiKB17hCQ==", - uint64_t{0x17fd05c3c560c320}, uint64_t{0x658e8a4e3b714d6c}}, - {"M6ZVVzsd7vAvbiACSYHioH/440dp4xG2mLlBnxgiqEvI/aIEGpD0Sf4VS0g=", - uint64_t{0x8b34200a6f8e90d9}, uint64_t{0xf391fb968e0eb398}}, - {"li3oFSXLXI+ubUVGJ4blP6mNinGKLHWkvGruun85AhVn6iuMtocbZPVhqxzn", - uint64_t{0x6be89e50818bdf69}, uint64_t{0x744a9ea0cc144bf2}}, - {"kFuQHuUCqBF3Tc3hO4dgdIp223ShaCoog48d5Do5zMqUXOh5XpGK1t5XtxnfGA==", - uint64_t{0xfb389773315b47d8}, uint64_t{0x12636f2be11012f1}}, - {"jWmOad0v0QhXVJd1OdGuBZtDYYS8wBVHlvOeTQx9ZZnm8wLEItPMeihj72E0nWY=", - uint64_t{0x4f2512a23f61efee}, uint64_t{0x29c57de825948f80}}, - {"z+DHU52HaOQdW4JrZwDQAebEA6rm13Zg/9lPYA3txt3NjTBqFZlOMvTRnVzRbl23", - uint64_t{0x59ccd92fc16c6fda}, uint64_t{0x58c6f99ab0d1c021}}, - {"MmBiGDfYeTayyJa/tVycg+rN7f9mPDFaDc+23j0TlW9094er0ADigsl4QX7V3gG/qw==", - uint64_t{0x25c5a7f5bd330919}, uint64_t{0x13e7b5a7b82fe3bb}}, - {"774RK+9rOL4iFvs1q2qpo/JVc/I39buvNjqEFDtDvyoB0FXxPI2vXqOrk08VPfIHkmU=", - uint64_t{0x51df4174d34c97d7}, uint64_t{0x10fbc87901e02b63}}, - {"+slatXiQ7/2lK0BkVUI1qzNxOOLP3I1iK6OfHaoxgqT63FpzbElwEXSwdsryq3UlHK0I", - uint64_t{0x80ce6d76f89cb57}, uint64_t{0xa24c9184901b748b}}, - {"64mVTbQ47dHjHlOHGS/hjJwr/" - "K2frCNpn87exOqMzNUVYiPKmhCbfS7vBUce5tO6Ec9osQ==", - uint64_t{0x20961c911965f684}, uint64_t{0xcac4fd4c5080e581}}, - {"fIsaG1r530SFrBqaDj1kqE0AJnvvK8MNEZbII2Yw1OK77v0V59xabIh0B5axaz/" - "+a2V5WpA=", - uint64_t{0x4e5b926ec83868e7}, uint64_t{0xc38bdb7483ba68e1}}, - {"PGih0zDEOWCYGxuHGDFu9Ivbff/" - "iE7BNUq65tycTR2R76TerrXALRosnzaNYO5fjFhTi+CiS", - uint64_t{0x3927b30b922eecef}, uint64_t{0xdb2a8069b2ceaffa}}, - {"RnpA/" - "zJnEnnLjmICORByRVb9bCOgxF44p3VMiW10G7PvW7IhwsWajlP9kIwNA9FjAD2GoQHk2Q=" - "=", - uint64_t{0xbd0291284a49b61c}, uint64_t{0xdf9fe91d0d1c7887}}, - {"qFklMceaTHqJpy2qavJE+EVBiNFOi6OxjOA3LeIcBop1K7w8xQi3TrDk+" - "BrWPRIbfprszSaPfrI=", - uint64_t{0x73a77c575bcc956}, uint64_t{0xe83f49e96e2e6a08}}, - {"cLbfUtLl3EcQmITWoTskUR8da/VafRDYF/ylPYwk7/" - "zazk6ssyrzxMN3mmSyvrXR2yDGNZ3WDrTT", - uint64_t{0x766a0e2ade6d09a6}, uint64_t{0xc69e61b62ca2b62}}, - {"s/" - "Jf1+" - "FbsbCpXWPTUSeWyMH6e4CvTFvPE5Fs6Z8hvFITGyr0dtukHzkI84oviVLxhM1xMxrMAy1db" - "w==", - uint64_t{0x2599f4f905115869}, uint64_t{0xb4a4f3f85f8298fe}}, - {"FvyQ00+j7nmYZVQ8hI1Edxd0AWplhTfWuFGiu34AK5X8u2hLX1bE97sZM0CmeLe+" - "7LgoUT1fJ/axybE=", - uint64_t{0xd8256e5444d21e53}, uint64_t{0x167a1b39e1e95f41}}, - {"L8ncxMaYLBH3g9buPu8hfpWZNlOF7nvWLNv9IozH07uQsIBWSKxoPy8+" - "LW4tTuzC6CIWbRGRRD1sQV/4", - uint64_t{0xf664a91333fb8dfd}, uint64_t{0xf8a2a5649855ee41}}, - {"CDK0meI07yrgV2kQlZZ+" - "wuVqhc2NmzqeLH7bmcA6kchsRWFPeVF5Wqjjaj556ABeUoUr3yBmfU3kWOakkg==", - uint64_t{0x9625b859be372cd1}, uint64_t{0x27992565b595c498}}, - {"d23/vc5ONh/" - "HkMiq+gYk4gaCNYyuFKwUkvn46t+dfVcKfBTYykr4kdvAPNXGYLjM4u1YkAEFpJP+" - "nX7eOvs=", - uint64_t{0x7b99940782e29898}, uint64_t{0x3e08cca5b71f9346}}, - {"NUR3SRxBkxTSbtQORJpu/GdR6b/h6sSGfsMj/KFd99ahbh+9r7LSgSGmkGVB/" - "mGoT0pnMTQst7Lv2q6QN6Vm", - uint64_t{0x4fe12fa5383b51a8}, uint64_t{0xad406b10c770a6d2}}, - {"2BOFlcI3Z0RYDtS9T9Ie9yJoXlOdigpPeeT+CRujb/" - "O39Ih5LPC9hP6RQk1kYESGyaLZZi3jtabHs7DiVx/VDg==", - uint64_t{0xe2ccb09ac0f5b4b6}, uint64_t{0xd1713ce6e552bcf2}}, - {"FF2HQE1FxEvWBpg6Z9zAMH+Zlqx8S1JD/" - "wIlViL6ZDZY63alMDrxB0GJQahmAtjlm26RGLnjW7jmgQ4Ie3I+014=", - uint64_t{0x7d0a37adbd7b753b}, uint64_t{0x753b287194c73ad3}}, - {"tHmO7mqVL/PX11nZrz50Hc+M17Poj5lpnqHkEN+4bpMx/" - "YGbkrGOaYjoQjgmt1X2QyypK7xClFrjeWrCMdlVYtbW", - uint64_t{0xd3ae96ef9f7185f2}, uint64_t{0x5ae41a95f600af1c}}, - {"/WiHi9IQcxRImsudkA/KOTqGe8/" - "gXkhKIHkjddv5S9hi02M049dIK3EUyAEjkjpdGLUs+BN0QzPtZqjIYPOgwsYE9g==", - uint64_t{0x4fb88ea63f79a0d8}, uint64_t{0x4a61163b86a8bb4c}}, - {"qds+1ExSnU11L4fTSDz/QE90g4Jh6ioqSh3KDOTOAo2pQGL1k/" - "9CCC7J23YF27dUTzrWsCQA2m4epXoCc3yPHb3xElA=", - uint64_t{0xed564e259bb5ebe9}, uint64_t{0x42eeaa79e760c7e4}}, - {"8FVYHx40lSQPTHheh08Oq0/" - "pGm2OlG8BEf8ezvAxHuGGdgCkqpXIueJBF2mQJhTfDy5NncO8ntS7vaKs7sCNdDaNGOEi", - uint64_t{0x3e3256b60c428000}, uint64_t{0x698df622ef465b0a}}, - {"4ZoEIrJtstiCkeew3oRzmyJHVt/pAs2pj0HgHFrBPztbQ10NsQ/" - "lM6DM439QVxpznnBSiHMgMQJhER+70l72LqFTO1JiIQ==", - uint64_t{0xfb05bad59ec8705}, uint64_t{0x157583111e1a6026}}, - {"hQPtaYI+wJyxXgwD5n8jGIKFKaFA/" - "P83KqCKZfPthnjwdOFysqEOYwAaZuaaiv4cDyi9TyS8hk5cEbNP/jrI7q6pYGBLbsM=", - uint64_t{0xafdc251dbf97b5f8}, uint64_t{0xaa1388f078e793e0}}, - {"S4gpMSKzMD7CWPsSfLeYyhSpfWOntyuVZdX1xSBjiGvsspwOZcxNKCRIOqAA0moUfOh3I5+" - "juQV4rsqYElMD/gWfDGpsWZKQ", - uint64_t{0x10ec9c92ddb5dcbc}, uint64_t{0xf10d68d0f3309360}}, - {"oswxop+" - "bthuDLT4j0PcoSKby4LhF47ZKg8K17xxHf74UsGCzTBbOz0MM8hQEGlyqDT1iUiAYnaPaUp" - "L2mRK0rcIUYA4qLt5uOw==", - uint64_t{0x9a767d5822c7dac4}, uint64_t{0x2af056184457a3de}}, - {"0II/" - "697p+" - "BtLSjxj5989OXI004TogEb94VUnDzOVSgMXie72cuYRvTFNIBgtXlKfkiUjeqVpd4a+" - "n5bxNOD1TGrjQtzKU5r7obo=", - uint64_t{0xee46254080d6e2db}, uint64_t{0x6d0058e1590b2489}}, - {"E84YZW2qipAlMPmctrg7TKlwLZ68l4L+c0xRDUfyyFrA4MAti0q9sHq3TDFviH0Y+" - "Kq3tEE5srWFA8LM9oomtmvm5PYxoaarWPLc", - uint64_t{0xbbb669588d8bf398}, uint64_t{0x638f287f68817f12}}, - {"x3pa4HIElyZG0Nj7Vdy9IdJIR4izLmypXw5PCmZB5y68QQ4uRaVVi3UthsoJROvbjDJkP2D" - "Q6L/eN8pFeLFzNPKBYzcmuMOb5Ull7w==", - uint64_t{0xdc2afaa529beef44}, uint64_t{0xc46b71fecefd5467}}, - {"jVDKGYIuWOP/" - "QKLdd2wi8B2VJA8Wh0c8PwrXJVM8FOGM3voPDVPyDJOU6QsBDPseoR8uuKd19OZ/" - "zAvSCB+zlf6upAsBlheUKgCfKww=", - uint64_t{0xf1f67391d45013a8}, uint64_t{0x2c8e94679d964e0a}}, - {"mkquunhmYe1aR2wmUz4vcvLEcKBoe6H+kjUok9VUn2+eTSkWs4oDDtJvNCWtY5efJwg/" - "j4PgjRYWtqnrCkhaqJaEvkkOwVfgMIwF3e+d", - uint64_t{0x16fce2b8c65a3429}, uint64_t{0x8612b797ce22503a}}, - {"fRelvKYonTQ+s+rnnvQw+JzGfFoPixtna0vzcSjiDqX5s2Kg2//" - "UGrK+AVCyMUhO98WoB1DDbrsOYSw2QzrcPe0+3ck9sePvb+Q/IRaHbw==", - uint64_t{0xf4b096699f49fe67}, uint64_t{0x59f929babfba7170}}, - {"DUwXFJzagljo44QeJ7/" - "6ZKw4QXV18lhkYT2jglMr8WB3CHUU4vdsytvw6AKv42ZcG6fRkZkq9fpnmXy6xG0aO3WPT1" - "eHuyFirAlkW+zKtwg=", - uint64_t{0xca584c4bc8198682}, uint64_t{0x9527556923fb49a0}}, - {"cYmZCrOOBBongNTr7e4nYn52uQUy2mfe48s50JXx2AZ6cRAt/" - "xRHJ5QbEoEJOeOHsJyM4nbzwFm++SlT6gFZZHJpkXJ92JkR86uS/eV1hJUR", - uint64_t{0xed269fc3818b6aad}, uint64_t{0x1039ab644f5e150b}}, - {"EXeHBDfhwzAKFhsMcH9+2RHwV+mJaN01+9oacF6vgm8mCXRd6jeN9U2oAb0of5c5cO4i+" - "Vb/LlHZSMI490SnHU0bejhSCC2gsC5d2K30ER3iNA==", - uint64_t{0x33f253cbb8fe66a8}, uint64_t{0x7816c83f3aa05e6d}}, - {"FzkzRYoNjkxFhZDso94IHRZaJUP61nFYrh5MwDwv9FNoJ5jyNCY/" - "eazPZk+tbmzDyJIGw2h3GxaWZ9bSlsol/vK98SbkMKCQ/wbfrXRLcDzdd/8=", - uint64_t{0xd0b76b2c1523d99c}, uint64_t{0xf51d2f564518c619}}, - {"Re4aXISCMlYY/XsX7zkIFR04ta03u4zkL9dVbLXMa/q6hlY/CImVIIYRN3VKP4pnd0AUr/" - "ugkyt36JcstAInb4h9rpAGQ7GMVOgBniiMBZ/MGU7H", - uint64_t{0xfd28f0811a2a237f}, uint64_t{0x67d494cff03ac004}}, - {"ueLyMcqJXX+MhO4UApylCN9WlTQ+" - "ltJmItgG7vFUtqs2qNwBMjmAvr5u0sAKd8jpzV0dDPTwchbIeAW5zbtkA2NABJV6hFM48ib" - "4/J3A5mseA3cS8w==", - uint64_t{0x6261fb136482e84}, uint64_t{0x2802d636ced1cfbb}}, - {"6Si7Yi11L+jZMkwaN+GUuzXMrlvEqviEkGOilNq0h8TdQyYKuFXzkYc/" - "q74gP3pVCyiwz9KpVGMM9vfnq36riMHRknkmhQutxLZs5fbmOgEO69HglCU=", - uint64_t{0x458efc750bca7c3a}, uint64_t{0xf64e20bad771cb12}}, - {"Q6AbOofGuTJOegPh9Clm/" - "9crtUMQqylKrTc1fhfJo1tqvpXxhU4k08kntL1RG7woRnFrVh2UoMrL1kjin+s9CanT+" - "y4hHwLqRranl9FjvxfVKm3yvg68", - uint64_t{0xa7e69ff84e5e7c27}, uint64_t{0xb9a6cf84a83e15e}}, - {"ieQEbIPvqY2YfIjHnqfJiO1/MIVRk0RoaG/WWi3kFrfIGiNLCczYoklgaecHMm/" - "1sZ96AjO+a5stQfZbJQwS7Sc1ODABEdJKcTsxeW2hbh9A6CFzpowP1A==", - uint64_t{0x3c59bfd0c29efe9e}, uint64_t{0x8da6630319609301}}, - {"zQUv8hFB3zh2GGl3KTvCmnfzE+" - "SUgQPVaSVIELFX5H9cE3FuVFGmymkPQZJLAyzC90Cmi8GqYCvPqTuAAB//" - "XTJxy4bCcVArgZG9zJXpjowpNBfr3ngWrSE=", - uint64_t{0x10befacc6afd298d}, uint64_t{0x40946a86e2a996f3}}, - {"US4hcC1+op5JKGC7eIs8CUgInjKWKlvKQkapulxW262E/" - "B2ye79QxOexf188u2mFwwe3WTISJHRZzS61IwljqAWAWoBAqkUnW8SHmIDwHUP31J0p5sGd" - "P47L", - uint64_t{0x41d5320b0a38efa7}, uint64_t{0xcab7f5997953fa76}}, - {"9bHUWFna2LNaGF6fQLlkx1Hkt24nrkLE2CmFdWgTQV3FFbUe747SSqYw6ebpTa07MWSpWRP" - "sHesVo2B9tqHbe7eQmqYebPDFnNqrhSdZwFm9arLQVs+7a3Ic6A==", - uint64_t{0x58db1c7450fe17f3}, uint64_t{0x39129ca0e04fc465}}, - {"Kb3DpHRUPhtyqgs3RuXjzA08jGb59hjKTOeFt1qhoINfYyfTt2buKhD6YVffRCPsgK9SeqZ" - "qRPJSyaqsa0ovyq1WnWW8jI/NhvAkZTVHUrX2pC+cD3OPYT05Dag=", - uint64_t{0x6098c055a335b7a6}, uint64_t{0x5238221fd685e1b8}}, - {"gzxyMJIPlU+bJBwhFUCHSofZ/" - "319LxqMoqnt3+L6h2U2+ZXJCSsYpE80xmR0Ta77Jq54o92SMH87HV8dGOaCTuAYF+" - "lDL42SY1P316Cl0sZTS2ow3ZqwGbcPNs/1", - uint64_t{0x1bbacec67845a801}, uint64_t{0x175130c407dbcaab}}, - {"uR7V0TW+FGVMpsifnaBAQ3IGlr1wx5sKd7TChuqRe6OvUXTlD4hKWy8S+" - "8yyOw8lQabism19vOQxfmocEOW/" - "vzY0pEa87qHrAZy4s9fH2Bltu8vaOIe+agYohhYORQ==", - uint64_t{0xc419cfc7442190}, uint64_t{0x2f20e7536c0b0df}}, - {"1UR5eoo2aCwhacjZHaCh9bkOsITp6QunUxHQ2SfeHv0imHetzt/" - "Z70mhyWZBalv6eAx+YfWKCUib2SHDtz/" - "A2dc3hqUWX5VfAV7FQsghPUAtu6IiRatq4YSLpDvKZBQ=", - uint64_t{0xc95e510d94ba270c}, uint64_t{0x2742cb488a04ad56}}, - {"opubR7H63BH7OtY+Avd7QyQ25UZ8kLBdFDsBTwZlY6gA/" - "u+x+" - "czC9AaZMgmQrUy15DH7YMGsvdXnviTtI4eVI4aF1H9Rl3NXMKZgwFOsdTfdcZeeHVRzBBKX" - "8jUfh1il", - uint64_t{0xff1ae05c98089c3f}, uint64_t{0xd6afb593879ff93b}}, - {"DC0kXcSXtfQ9FbSRwirIn5tgPri0sbzHSa78aDZVDUKCMaBGyFU6BmrulywYX8yzvwprdLs" - "oOwTWN2wMjHlPDqrvVHNEjnmufRDblW+nSS+xtKNs3N5xsxXdv6JXDrAB/Q==", - uint64_t{0x90c02b8dceced493}, uint64_t{0xf50ad64caac0ca7f}}, - {"BXRBk+3wEP3Lpm1y75wjoz+PgB0AMzLe8tQ1AYU2/" - "oqrQB2YMC6W+9QDbcOfkGbeH+b7IBkt/" - "gwCMw2HaQsRFEsurXtcQ3YwRuPz5XNaw5NAvrNa67Fm7eRzdE1+hWLKtA8=", - uint64_t{0x9f8a76697ab1aa36}, uint64_t{0x2ade95c4261364ae}}, - {"RRBSvEGYnzR9E45Aps/+WSnpCo/X7gJLO4DRnUqFrJCV/kzWlusLE/" - "6ZU6RoUf2ROwcgEvUiXTGjLs7ts3t9SXnJHxC1KiOzxHdYLMhVvgNd3hVSAXODpKFSkVXND" - "55G2L1W", - uint64_t{0x6ba1bf3d811a531d}, uint64_t{0x5c4f3299faacd07a}}, - {"jeh6Qazxmdi57pa9S3XSnnZFIRrnc6s8QLrah5OX3SB/V2ErSPoEAumavzQPkdKF1/" - "SfvmdL+qgF1C+Yawy562QaFqwVGq7+tW0yxP8FStb56ZRgNI4IOmI30s1Ei7iops9Uuw==", - uint64_t{0x6a418974109c67b4}, uint64_t{0xfffe3bff0ae5e9bc}}, - {"6QO5nnDrY2/" - "wrUXpltlKy2dSBcmK15fOY092CR7KxAjNfaY+" - "aAmtWbbzQk3MjBg03x39afSUN1fkrWACdyQKRaGxgwq6MGNxI6W+8DLWJBHzIXrntrE/" - "ml6fnNXEpxplWJ1vEs4=", - uint64_t{0x8472f1c2b3d230a3}, uint64_t{0x1db785c0005166e4}}, - {"0oPxeEHhqhcFuwonNfLd5jF3RNATGZS6NPoS0WklnzyokbTqcl4BeBkMn07+fDQv83j/" - "BpGUwcWO05f3+DYzocfnizpFjLJemFGsls3gxcBYxcbqWYev51tG3lN9EvRE+X9+Pwww", - uint64_t{0x5e06068f884e73a7}, uint64_t{0xea000d962ad18418}}, - {"naSBSjtOKgAOg8XVbR5cHAW3Y+QL4Pb/JO9/" - "oy6L08wvVRZqo0BrssMwhzBP401Um7A4ppAupbQeJFdMrysY34AuSSNvtNUy5VxjNECwiNt" - "gwYHw7yakDUv8WvonctmnoSPKENegQg==", - uint64_t{0x55290b1a8f170f59}, uint64_t{0xe42aef38359362d9}}, - {"vPyl8DxVeRe1OpilKb9KNwpGkQRtA94UpAHetNh+" - "95V7nIW38v7PpzhnTWIml5kw3So1Si0TXtIUPIbsu32BNhoH7QwFvLM+" - "JACgSpc5e3RjsL6Qwxxi11npwxRmRUqATDeMUfRAjxg=", - uint64_t{0x5501cfd83dfe706a}, uint64_t{0xc8e95657348a3891}}, - {"QC9i2GjdTMuNC1xQJ74ngKfrlA4w3o58FhvNCltdIpuMhHP1YsDA78scQPLbZ3OCUgeQguY" - "f/vw6zAaVKSgwtaykqg5ka/4vhz4hYqWU5ficdXqClHl+zkWEY26slCNYOM5nnDlly8Cj", - uint64_t{0xe43ed13d13a66990}, uint64_t{0xc162eca864f238c6}}, - {"7CNIgQhAHX27nxI0HeB5oUTnTdgKpRDYDKwRcXfSFGP1XeT9nQF6WKCMjL1tBV6x7KuJ91G" - "Zz11F4c+8s+MfqEAEpd4FHzamrMNjGcjCyrVtU6y+7HscMVzr7Q/" - "ODLcPEFztFnwjvCjmHw==", - uint64_t{0xdf43bc375cf5283f}, uint64_t{0xbe1fb373e20579ad}}, - {"Qa/hC2RPXhANSospe+gUaPfjdK/yhQvfm4cCV6/pdvCYWPv8p1kMtKOX3h5/" - "8oZ31fsmx4Axphu5qXJokuhZKkBUJueuMpxRyXpwSWz2wELx5glxF7CM0Fn+" - "OevnkhUn5jsPlG2r5jYlVn8=", - uint64_t{0x8112b806d288d7b5}, uint64_t{0x628a1d4f40aa6ffd}}, - {"kUw/0z4l3a89jTwN5jpG0SHY5km/" - "IVhTjgM5xCiPRLncg40aqWrJ5vcF891AOq5hEpSq0bUCJUMFXgct7kvnys905HjerV7Vs1G" - "y84tgVJ70/2+pAZTsB/PzNOE/G6sOj4+GbTzkQu819OLB", - uint64_t{0xd52a18abb001cb46}, uint64_t{0xa87bdb7456340f90}}, - {"VDdfSDbO8Tdj3T5W0XM3EI7iHh5xpIutiM6dvcJ/fhe23V/srFEkDy5iZf/" - "VnA9kfi2C79ENnFnbOReeuZW1b3MUXB9lgC6U4pOTuC+" - "jHK3Qnpyiqzj7h3ISJSuo2pob7vY6VHZo6Fn7exEqHg==", - uint64_t{0xe12b76a2433a1236}, uint64_t{0x5960ef3ba982c801}}, - {"Ldfvy3ORdquM/R2fIkhH/ONi69mcP1AEJ6n/" - "oropwecAsLJzQSgezSY8bEiEs0VnFTBBsW+RtZY6tDj03fnb3amNUOq1b7jbqyQkL9hpl+" - "2Z2J8IaVSeownWl+bQcsR5/xRktIMckC5AtF4YHfU=", - uint64_t{0x175bf7319cf1fa00}, uint64_t{0x5026586df9a431ec}}, - {"BrbNpb42+" - "VzZAjJw6QLirXzhweCVRfwlczzZ0VX2xluskwBqyfnGovz5EuX79JJ31VNXa5hTkAyQat3l" - "YKRADTdAdwE5PqM1N7YaMqqsqoAAAeuYVXuk5eWCykYmClNdSspegwgCuT+403JigBzi", - uint64_t{0xd63d57b3f67525ae}, uint64_t{0xfe4b8a20fdf0840b}}, - {"gB3NGHJJvVcuPyF0ZSvHwnWSIfmaI7La24VMPQVoIIWF7Z74NltPZZpx2f+cocESM+" - "ILzQW9p+BC8x5IWz7N4Str2WLGKMdgmaBfNkEhSHQDU0IJEOnpUt0HmjhFaBlx0/" - "LTmhua+rQ6Wup8ezLwfg==", - uint64_t{0x933faea858832b73}, uint64_t{0xdcb761867da7072f}}, - {"hTKHlRxx6Pl4gjG+6ksvvj0CWFicUg3WrPdSJypDpq91LUWRni2KF6+" - "81ZoHBFhEBrCdogKqeK+hy9bLDnx7g6rAFUjtn1+cWzQ2YjiOpz4+" - "ROBB7lnwjyTGWzJD1rXtlso1g2qVH8XJVigC5M9AIxM=", - uint64_t{0x53d061e5f8e7c04f}, uint64_t{0xc10d4653667275b7}}, - {"IWQBelSQnhrr0F3BhUpXUIDauhX6f95Qp+A0diFXiUK7irwPG1oqBiqHyK/SH/" - "9S+" - "rln9DlFROAmeFdH0OCJi2tFm4afxYzJTFR4HnR4cG4x12JqHaZLQx6iiu6CE3rtWBVz99oA" - "wCZUOEXIsLU24o2Y", - uint64_t{0xdb4124556dd515e0}, uint64_t{0x727720deec13110b}}, - {"TKo+l+" - "1dOXdLvIrFqeLaHdm0HZnbcdEgOoLVcGRiCbAMR0j5pIFw8D36tefckAS1RCFOH5IgP8yiF" - "T0Gd0a2hI3+" - "fTKA7iK96NekxWeoeqzJyctc6QsoiyBlkZerRxs5RplrxoeNg29kKDTM0K94mnhD9g==", - uint64_t{0x4fb31a0dd681ee71}, uint64_t{0x710b009662858dc9}}, - {"YU4e7G6EfQYvxCFoCrrT0EFgVLHFfOWRTJQJ5gxM3G2b+" - "1kJf9YPrpsxF6Xr6nYtS8reEEbDoZJYqnlk9lXSkVArm88Cqn6d25VCx3+" - "49MqC0trIlXtb7SXUUhwpJK16T0hJUfPH7s5cMZXc6YmmbFuBNPE=", - uint64_t{0x27cc72eefa138e4c}, uint64_t{0xfbf8f7a3ecac1eb7}}, - {"/I/" - "eImMwPo1U6wekNFD1Jxjk9XQVi1D+" - "FPdqcHifYXQuP5aScNQfxMAmaPR2XhuOQhADV5tTVbBKwCDCX4E3jcDNHzCiPvViZF1W27t" - "xaf2BbFQdwKrNCmrtzcluBFYu0XZfc7RU1RmxK/RtnF1qHsq/O4pp", - uint64_t{0x44bc2dfba4bd3ced}, uint64_t{0xb6fc4fcd0722e3df}}, - {"CJTT9WGcY2XykTdo8KodRIA29qsqY0iHzWZRjKHb9alwyJ7RZAE3V5Juv4MY3MeYEr1EPCC" - "MxO7yFXqT8XA8YTjaMp3bafRt17Pw8JC4iKJ1zN+WWKOESrj+" - "3aluGQqn8z1EzqY4PH7rLG575PYeWsP98BugdA==", - uint64_t{0x242da1e3a439bed8}, uint64_t{0x7cb86dcc55104aac}}, - {"ZlhyQwLhXQyIUEnMH/" - "AEW27vh9xrbNKJxpWGtrEmKhd+nFqAfbeNBQjW0SfG1YI0xQkQMHXjuTt4P/" - "EpZRtA47ibZDVS8TtaxwyBjuIDwqcN09eCtpC+Ls+" - "vWDTLmBeDM3u4hmzz4DQAYsLiZYSJcldg9Q3wszw=", - uint64_t{0xdc559c746e35c139}, uint64_t{0x19e71e9b45c3a51e}}, - {"v2KU8y0sCrBghmnm8lzGJlwo6D6ObccAxCf10heoDtYLosk4ztTpLlpSFEyu23MLA1tJkcg" - "Rko04h19QMG0mOw/" - "wc93EXAweriBqXfvdaP85sZABwiKO+6rtS9pacRVpYYhHJeVTQ5NzrvBvi1huxAr+" - "xswhVMfL", - uint64_t{0xd0b0350275b9989}, uint64_t{0x51de38573c2bea48}}, - {"QhKlnIS6BuVCTQsnoE67E/" - "yrgogE8EwO7xLaEGei26m0gEU4OksefJgppDh3X0x0Cs78Dr9IHK5b977CmZlrTRmwhlP8p" - "M+UzXPNRNIZuN3ntOum/QhUWP8SGpirheXENWsXMQ/" - "nxtxakyEtrNkKk471Oov9juP8oQ==", - uint64_t{0xb04489e41d17730c}, uint64_t{0xa73ab6996d6df158}}, - {"/ZRMgnoRt+Uo6fUPr9FqQvKX7syhgVqWu+" - "WUSsiQ68UlN0efSP6Eced5gJZL6tg9gcYJIkhjuQNITU0Q3TjVAnAcobgbJikCn6qZ6pRxK" - "BY4MTiAlfGD3T7R7hwJwx554MAy++Zb/YUFlnCaCJiwQMnowF7aQzwYFCo=", - uint64_t{0x2217285eb4572156}, uint64_t{0x55ef2b8c930817b2}}, - {"NB7tU5fNE8nI+SXGfipc7sRkhnSkUF1krjeo6k+8FITaAtdyz+" - "o7mONgXmGLulBPH9bEwyYhKNVY0L+njNQrZ9YC2aXsFD3PdZsxAFaBT3VXEzh+" - "NGBTjDASNL3mXyS8Yv1iThGfHoY7T4aR0NYGJ+k+pR6f+KrPC96M", - uint64_t{0x12c2e8e68aede73b}, uint64_t{0xb2850bf5fae87157}}, - {"8T6wrqCtEO6/rwxF6lvMeyuigVOLwPipX/FULvwyu+1wa5sQGav/" - "2FsLHUVn6cGSi0LlFwLewGHPFJDLR0u4t7ZUyM//" - "x6da0sWgOa5hzDqjsVGmjxEHXiaXKW3i4iSZNuxoNbMQkIbVML+" - "DkYu9ND0O2swg4itGeVSzXA==", - uint64_t{0x4d612125bdc4fd00}, uint64_t{0xecf3de1acd04651f}}, - {"Ntf1bMRdondtMv1CYr3G80iDJ4WSAlKy5H34XdGruQiCrnRGDBa+" - "eUi7vKp4gp3BBcVGl8eYSasVQQjn7MLvb3BjtXx6c/" - "bCL7JtpzQKaDnPr9GWRxpBXVxKREgMM7d8lm35EODv0w+" - "hQLfVSh8OGs7fsBb68nNWPLeeSOo=", - uint64_t{0x81826b553954464e}, uint64_t{0xcc0a40552559ff32}}, - {"VsSAw72Ro6xks02kaiLuiTEIWBC5bgqr4WDnmP8vglXzAhixk7td926rm9jNimL+" - "kroPSygZ9gl63aF5DCPOACXmsbmhDrAQuUzoh9ZKhWgElLQsrqo1KIjWoZT5b5QfVUXY9lS" - "IBg3U75SqORoTPq7HalxxoIT5diWOcJQi", - uint64_t{0xc2e5d345dc0ddd2d}, uint64_t{0xc385c374f20315b1}}, - {"j+loZ+C87+" - "bJxNVebg94gU0mSLeDulcHs84tQT7BZM2rzDSLiCNxUedHr1ZWJ9ejTiBa0dqy2I2ABc++" - "xzOLcv+//YfibtjKtYggC6/3rv0XCc7xu6d/" - "O6xO+XOBhOWAQ+IHJVHf7wZnDxIXB8AUHsnjEISKj7823biqXjyP3g==", - uint64_t{0x3da6830a9e32631e}, uint64_t{0xb90208a4c7234183}}, - {"f3LlpcPElMkspNtDq5xXyWU62erEaKn7RWKlo540gR6mZsNpK1czV/" - "sOmqaq8XAQLEn68LKj6/" - "cFkJukxRzCa4OF1a7cCAXYFp9+wZDu0bw4y63qbpjhdCl8GO6Z2lkcXy7KOzbPE01ukg7+" - "gN+7uKpoohgAhIwpAKQXmX5xtd0=", - uint64_t{0xc9ae5c8759b4877a}, uint64_t{0x58aa1ca7a4c075d9}}, - }; - - for (const auto& expected_result : expected_results) { - std::string str; - ASSERT_TRUE(absl::Base64Unescape(expected_result.base64_data, &str)); - EXPECT_EQ(absl::hash_internal::Wyhash(str.data(), str.size(), - expected_result.seed, kSalt), - expected_result.hash); - } -} - -} // namespace diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel index 45a95292..f549af66 100644 --- a/absl/time/internal/cctz/BUILD.bazel +++ b/absl/time/internal/cctz/BUILD.bazel @@ -26,14 +26,14 @@ filegroup( config_setting( name = "osx", constraint_values = [ - "@bazel_tools//platforms:osx", + "@platforms//os:osx", ], ) config_setting( name = "ios", constraint_values = [ - "@bazel_tools//platforms:ios", + "@platforms//os:ios", ], ) -- cgit v1.2.3 From c1aa431c071af43d7935bc0d44d560ea851a7696 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 17 Aug 2021 13:00:49 -0700 Subject: Export of internal Abseil changes -- aabb5093ff380fc60d9a75ace279b620fdc4bff9 by Abseil Team : Demangle Clang-specific " ::= cp * E" Cf. https://clang.llvm.org/doxygen/ItaniumMangle_8cpp_source.html#l04338 PiperOrigin-RevId: 391358031 -- 34dc7baa38f74a8c78b91ac94486707347a85e35 by Derek Mauro : Internal change PiperOrigin-RevId: 391282565 GitOrigin-RevId: aabb5093ff380fc60d9a75ace279b620fdc4bff9 Change-Id: I6d3e235a9c0a1b67a43071de205fed0fefe12912 --- absl/debugging/internal/demangle.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc index 5cd56320..93ae3279 100644 --- a/absl/debugging/internal/demangle.cc +++ b/absl/debugging/internal/demangle.cc @@ -1617,6 +1617,7 @@ static bool ParseUnresolvedName(State *state) { // ::= <2-ary operator-name> // ::= <3-ary operator-name> // ::= cl + E +// ::= cp * E # Clang-specific. // ::= cv # type (expression) // ::= cv _ * E # type (expr-list) // ::= st @@ -1639,14 +1640,23 @@ static bool ParseExpression(State *state) { return true; } - // Object/function call expression. ParseState copy = state->parse_state; + + // Object/function call expression. if (ParseTwoCharToken(state, "cl") && OneOrMore(ParseExpression, state) && ParseOneCharToken(state, 'E')) { return true; } state->parse_state = copy; + // Clang-specific "cp * E" + // https://clang.llvm.org/doxygen/ItaniumMangle_8cpp_source.html#l04338 + if (ParseTwoCharToken(state, "cp") && ParseSimpleId(state) && + ZeroOrMore(ParseExpression, state) && ParseOneCharToken(state, 'E')) { + return true; + } + state->parse_state = copy; + // Function-param expression (level 0). if (ParseTwoCharToken(state, "fp") && Optional(ParseCVQualifiers(state)) && Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) { -- cgit v1.2.3 From a05366d851c5cb88065272f951e03955197e7c11 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 19 Aug 2021 13:34:28 -0700 Subject: Export of internal Abseil changes -- 04cb3b22497190170aa5b774e98080c5de2ba60b by Abseil Team : Alternative bit mixer for LowLevelHash on ARM LowLevelHash's bit-mixer is inefficient on ARM because it calculates a 128-bit product of two 64-bit numbers. On ARM, this requires a sequence of two instructions with a high combined latency and poor throughput. This change provides alternative bit-mixing code for ARM that uses only 64-bit arithmetic (multiplication, xor, and left-shifts) and speeds things up considerably. The bit-mixing code for ARM was inspired by by Woothash[1] and xxh3[1]. Once I landed on a sequence of operations that provided good mixing, I used a test harness to search for the combination of shift / rotate factors that provided the best mixing, as indicated by SMHasher hash quality tests. The new mixing code passes 13 out of 15 of the hash quality test suites in SMHasher, with the two failures being in the noise range: e.g. 1 collision vs. zero expected in a keyset of ~8m keys. [1]: https://github.com/tommyettinger/waterhash/blob/49f5cf0b63b9/woothash.h#L16-L20 [2]: https://github.com/Cyan4973/xxHash/blob/6853ddc36e46/xxhash.h#L3240-L3265 PiperOrigin-RevId: 391833008 -- 17a4de1f9d623155c75b19285d414cd55a487cd6 by Saleem Abdulrasool : debugging: add support for unwinding on RISCV Linux This adds partial support for unwinding the RISCV call stack. It is largely duplicated from the AArch64 support with alterations for the ELF RISCV psABI. This covers RISCV64 and RISCV32, though not the ILP32E calling convention. PiperOrigin-RevId: 391818522 -- 32c93e449327b2cea32b32f6365e84b420fe1ed3 by Gennadiy Rozental : New storage for types smaller than 8 bytes. Also adding new read interface for types smaller than or rqual to 8 bytes to avoid passing the pointer. PiperOrigin-RevId: 391726822 -- e987ac08a7787801cbfc7d7c96649e97fa8cff1a by Abseil Team : Extern template `find_first_non_full` to reduce linkage size for TU with single not inlined function. PiperOrigin-RevId: 391718862 -- 73af9bfcb5bf045089133e18bbd20eb5bb699172 by Gennadiy Rozental : Make most non-mutable most int128 methods and friend free functions constexpr. Some functions are implemented offline (at least in some configurations) and can't be made constexpr. Mutable methods can't be made constexpr until we drop c++11 support. Fixes #978 PiperOrigin-RevId: 391706535 GitOrigin-RevId: 04cb3b22497190170aa5b774e98080c5de2ba60b Change-Id: If051fad5ff004e2e82fa53618fc04a6fe3d2d4be --- absl/base/log_severity_test.cc | 6 +- absl/container/internal/raw_hash_set.cc | 2 + absl/container/internal/raw_hash_set.h | 6 + absl/debugging/BUILD.bazel | 1 + absl/debugging/CMakeLists.txt | 1 + absl/debugging/internal/stacktrace_config.h | 3 + absl/debugging/internal/stacktrace_riscv-inl.inc | 234 +++++++++++ absl/debugging/stacktrace.cc | 1 + absl/flags/flag_test.cc | 37 +- absl/flags/internal/flag.cc | 91 +++-- absl/flags/internal/flag.h | 71 +++- absl/hash/BUILD.bazel | 1 + absl/hash/CMakeLists.txt | 1 + absl/hash/internal/low_level_hash.cc | 12 + absl/hash/internal/low_level_hash_test.cc | 484 +++++++++++++---------- absl/numeric/int128.h | 128 +++--- absl/numeric/int128_have_intrinsic.inc | 44 +-- absl/numeric/int128_no_intrinsic.inc | 133 +++---- 18 files changed, 840 insertions(+), 416 deletions(-) create mode 100644 absl/debugging/internal/stacktrace_riscv-inl.inc (limited to 'absl/debugging') diff --git a/absl/base/log_severity_test.cc b/absl/base/log_severity_test.cc index 2c6872b0..55b26d17 100644 --- a/absl/base/log_severity_test.cc +++ b/absl/base/log_severity_test.cc @@ -52,9 +52,9 @@ TEST(StreamTest, Works) { Eq("absl::LogSeverity(4)")); } -static_assert( - absl::flags_internal::FlagUseOneWordStorage::value, - "Flags of type absl::LogSeverity ought to be lock-free."); +static_assert(absl::flags_internal::FlagUseValueAndInitBitStorage< + absl::LogSeverity>::value, + "Flags of type absl::LogSeverity ought to be lock-free."); using ParseFlagFromOutOfRangeIntegerTest = TestWithParam; INSTANTIATE_TEST_SUITE_P( diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 3c72c41a..687bcb8a 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -59,6 +59,8 @@ void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) { std::memcpy(ctrl + capacity + 1, ctrl, NumClonedBytes()); ctrl[capacity] = ctrl_t::kSentinel; } +// Extern template instantiotion for inline function. +template FindInfo find_first_non_full(const ctrl_t*, size_t, size_t); } // namespace container_internal ABSL_NAMESPACE_END diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index ade2f584..18b1f5a4 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -570,6 +570,7 @@ inline probe_seq probe(const ctrl_t* ctrl, size_t hash, // - the input is already a set // - there are enough slots // - the element with the hash is not in the table +template inline FindInfo find_first_non_full(const ctrl_t* ctrl, size_t hash, size_t capacity) { auto seq = probe(ctrl, hash, capacity); @@ -593,6 +594,11 @@ inline FindInfo find_first_non_full(const ctrl_t* ctrl, size_t hash, } } +// Extern template for inline function keep possibility of inlining. +// When compiler decided to not inline, no symbols will be added to the +// corresponding translation unit. +extern template FindInfo find_first_non_full(const ctrl_t*, size_t, size_t); + // Reset all ctrl bytes back to ctrl_t::kEmpty, except the sentinel. inline void ResetCtrl(size_t capacity, ctrl_t* ctrl, const void* slot, size_t slot_size) { diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index a8c51a5c..b536a044 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -37,6 +37,7 @@ cc_library( "internal/stacktrace_emscripten-inl.inc", "internal/stacktrace_generic-inl.inc", "internal/stacktrace_powerpc-inl.inc", + "internal/stacktrace_riscv-inl.inc", "internal/stacktrace_unimplemented-inl.inc", "internal/stacktrace_win32-inl.inc", "internal/stacktrace_x86-inl.inc", diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index 760772f3..b16fa007 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -25,6 +25,7 @@ absl_cc_library( "internal/stacktrace_emscripten-inl.inc" "internal/stacktrace_generic-inl.inc" "internal/stacktrace_powerpc-inl.inc" + "internal/stacktrace_riscv-inl.inc" "internal/stacktrace_unimplemented-inl.inc" "internal/stacktrace_win32-inl.inc" "internal/stacktrace_x86-inl.inc" diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h index 6cceef26..29b26bdd 100644 --- a/absl/debugging/internal/stacktrace_config.h +++ b/absl/debugging/internal/stacktrace_config.h @@ -65,6 +65,9 @@ #elif defined(__aarch64__) #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_aarch64-inl.inc" +#elif defined(__riscv) +#define ABSL_STACKTRACE_INL_HEADER \ + "absl/debugging/internal/stacktrace_riscv-inl.inc" #elif defined(__has_include) #if __has_include() // Note: When using glibc this may require -funwind-tables to function properly. diff --git a/absl/debugging/internal/stacktrace_riscv-inl.inc b/absl/debugging/internal/stacktrace_riscv-inl.inc new file mode 100644 index 00000000..8cbc7854 --- /dev/null +++ b/absl/debugging/internal/stacktrace_riscv-inl.inc @@ -0,0 +1,234 @@ +// Copyright 2021 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_RISCV_INL_H_ +#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_RISCV_INL_H_ + +// Generate stack trace for riscv + +#include + +#include "absl/base/config.h" +#if defined(__linux__) +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/debugging/internal/address_is_readable.h" +#include "absl/debugging/internal/vdso_support.h" +#include "absl/debugging/stacktrace.h" + +static const uintptr_t kUnknownFrameSize = 0; + +#if defined(__linux__) +// Returns the address of the VDSO __kernel_rt_sigreturn function, if present. +static const unsigned char *GetKernelRtSigreturnAddress() { + constexpr uintptr_t kImpossibleAddress = 0; + ABSL_CONST_INIT static std::atomic memoized(kImpossibleAddress); + uintptr_t address = memoized.load(std::memory_order_relaxed); + if (address != kImpossibleAddress) { + return reinterpret_cast(address); + } + + address = reinterpret_cast(nullptr); + +#if ABSL_HAVE_VDSO_SUPPORT + absl::debugging_internal::VDSOSupport vdso; + if (vdso.IsPresent()) { + absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info; + // Symbol versioning pulled from arch/riscv/kernel/vdso/vdso.lds at v5.10. + auto lookup = [&](int type) { + return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_4.15", type, + &symbol_info); + }; + if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) || + symbol_info.address == nullptr) { + // Unexpected: VDSO is present, yet the expected symbol is missing or + // null. + assert(false && "VDSO is present, but doesn't have expected symbol"); + } else { + if (reinterpret_cast(symbol_info.address) != + kImpossibleAddress) { + address = reinterpret_cast(symbol_info.address); + } else { + assert(false && "VDSO returned invalid address"); + } + } + } +#endif + + memoized.store(address, std::memory_order_relaxed); + return reinterpret_cast(address); +} +#endif // __linux__ + +// Compute the size of a stack frame in [low..high). We assume that low < high. +// Return size of kUnknownFrameSize. +template +static inline uintptr_t ComputeStackFrameSize(const T *low, const T *high) { + const char *low_char_ptr = reinterpret_cast(low); + const char *high_char_ptr = reinterpret_cast(high); + return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize; +} + +// Given a pointer to a stack frame, locate and return the calling stackframe, +// or return null if no stackframe can be found. Perform sanity checks (the +// strictness of which is controlled by the boolean parameter +// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. +template +ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. +static void ** NextStackFrame(void **old_frame_pointer, const void *uc) { + // . + // . + // . + // +-> +----------------+ + // | | return address | + // | | previous fp | + // | | ... | + // | +----------------+ <-+ + // | | return address | | + // +---|- previous fp | | + // | ... | | + // $fp ->|----------------+ | + // | return address | | + // | previous fp -|---+ + // $sp ->| ... | + // +----------------+ + void **new_frame_pointer = reinterpret_cast(old_frame_pointer[-2]); + bool check_frame_size = true; + +#if defined(__linux__) + if (WITH_CONTEXT && uc != nullptr) { + // Check to see if next frame's return address is __kernel_rt_sigreturn. + if (old_frame_pointer[-1] == GetKernelRtSigreturnAddress()) { + const ucontext_t *ucv = static_cast(uc); + // old_frame_pointer is not suitable for unwinding, look at ucontext to + // discover frame pointer before signal. + // + // RISCV ELF psABI has the frame pointer at x8/fp/s0. + // -- RISCV psABI Table 18.2 + void **const pre_signal_frame_pointer = + reinterpret_cast(ucv->uc_mcontext.__gregs[8]); + + // Check the alleged frame pointer is actually readable. This is to + // prevent "double fault" in case we hit the first fault due to stack + // corruption. + if (!absl::debugging_internal::AddressIsReadable( + pre_signal_frame_pointer)) + return nullptr; + + // Alleged frame pointer is readable, use it for further unwinding. + new_frame_pointer = pre_signal_frame_pointer; + + // Skip frame size check if we return from a signal. We may be using an + // alterate stack for signals. + check_frame_size = false; + } + } +#endif + + // The RISCV ELF psABI mandates that the stack pointer is always 16-byte + // aligned. + // FIXME(abdulras) this doesn't hold for ILP32E which only mandates a 4-byte + // alignment. + if ((reinterpret_cast(new_frame_pointer) & 15) != 0) + return nullptr; + + // Check frame size. In strict mode, we assume frames to be under 100,000 + // bytes. In non-strict mode, we relax the limit to 1MB. + if (check_frame_size) { + const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000; + const uintptr_t frame_size = + ComputeStackFrameSize(old_frame_pointer, new_frame_pointer); + if (frame_size == kUnknownFrameSize || frame_size > max_size) + return nullptr; + } + + return new_frame_pointer; +} + +template +ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. +static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, + const void *ucp, int *min_dropped_frames) { +#if defined(__GNUC__) + void **frame_pointer = reinterpret_cast(__builtin_frame_address(0)); +#else +#error reading stack pointer not yet supported on this platform +#endif + + skip_count++; // Skip the frame for this function. + int n = 0; + + // The `frame_pointer` that is computed here points to the top of the frame. + // The two words preceding the address are the return address and the previous + // frame pointer. To find a PC value associated with the current frame, we + // need to go down a level in the call chain. So we remember the return + // address of the last frame seen. This does not work for the first stack + // frame, which belongs to `UnwindImp()` but we skip the frame for + // `UnwindImp()` anyway. + void *prev_return_address = nullptr; + + while (frame_pointer && n < max_depth) { + // The absl::GetStackFrames routine si called when we are in some + // informational context (the failure signal handler for example). Use the + // non-strict unwinding rules to produce a stack trace that is as complete + // as possible (even if it contains a few bogus entries in some rare cases). + void **next_frame_pointer = + NextStackFrame(frame_pointer, ucp); + + if (skip_count > 0) { + skip_count--; + } else { + result[n] = prev_return_address; + if (IS_STACK_FRAMES) { + sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer); + } + n++; + } + prev_return_address = frame_pointer[-1]; + frame_pointer = next_frame_pointer; + } + if (min_dropped_frames != nullptr) { + // Implementation detail: we clamp the max of frames we are willing to + // count, so as not to spend too much time in the loop below. + const int kMaxUnwind = 200; + int j = 0; + for (; frame_pointer != nullptr && j < kMaxUnwind; j++) { + frame_pointer = + NextStackFrame(frame_pointer, ucp); + } + *min_dropped_frames = j; + } + return n; +} + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace debugging_internal { +bool StackTraceWorksForTest() { return true; } +} // namespace debugging_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc index 5358b942..ff8069f8 100644 --- a/absl/debugging/stacktrace.cc +++ b/absl/debugging/stacktrace.cc @@ -52,6 +52,7 @@ # include "absl/debugging/internal/stacktrace_emscripten-inl.inc" # include "absl/debugging/internal/stacktrace_generic-inl.inc" # include "absl/debugging/internal/stacktrace_powerpc-inl.inc" +# include "absl/debugging/internal/stacktrace_riscv-inl.inc" # include "absl/debugging/internal/stacktrace_unimplemented-inl.inc" # include "absl/debugging/internal/stacktrace_win32-inl.inc" # include "absl/debugging/internal/stacktrace_x86-inl.inc" diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index ba81317b..6e974a5b 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -103,9 +103,9 @@ struct S2 { TEST_F(FlagTest, Traits) { EXPECT_EQ(flags::StorageKind(), - flags::FlagValueStorageKind::kOneWordAtomic); + flags::FlagValueStorageKind::kValueAndInitBit); EXPECT_EQ(flags::StorageKind(), - flags::FlagValueStorageKind::kOneWordAtomic); + flags::FlagValueStorageKind::kValueAndInitBit); EXPECT_EQ(flags::StorageKind(), flags::FlagValueStorageKind::kOneWordAtomic); EXPECT_EQ(flags::StorageKind(), @@ -724,6 +724,8 @@ ABSL_FLAG(CustomUDT, test_flag_custom_udt, CustomUDT(), "test flag custom UDT"); namespace { TEST_F(FlagTest, TestCustomUDT) { + EXPECT_EQ(flags::StorageKind(), + flags::FlagValueStorageKind::kOneWordAtomic); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(1, 1)); absl::SetFlag(&FLAGS_test_flag_custom_udt, CustomUDT(2, 3)); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(2, 3)); @@ -944,3 +946,34 @@ TEST_F(FlagTest, TestNonTriviallyCopyableUDT) { } } // namespace + +// -------------------------------------------------------------------- + +namespace { + +enum TestE { A = 1, B = 2, C = 3 }; + +struct EnumWrapper { + EnumWrapper() : e(A) {} + + TestE e; +}; + +bool AbslParseFlag(absl::string_view, EnumWrapper*, std::string*) { + return true; +} +std::string AbslUnparseFlag(const EnumWrapper&) { return ""; } + +} // namespace + +ABSL_FLAG(EnumWrapper, test_enum_wrapper_flag, {}, "help"); + +TEST_F(FlagTest, TesTypeWrappingEnum) { + EnumWrapper value = absl::GetFlag(FLAGS_test_enum_wrapper_flag); + EXPECT_EQ(value.e, A); + + value.e = B; + absl::SetFlag(&FLAGS_test_enum_wrapper_flag, value); + value = absl::GetFlag(FLAGS_test_enum_wrapper_flag); + EXPECT_EQ(value.e, B); +} diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc index f83c1fe7..1515022d 100644 --- a/absl/flags/internal/flag.cc +++ b/absl/flags/internal/flag.cc @@ -145,12 +145,7 @@ void FlagImpl::Init() { auto def_kind = static_cast(def_kind_); switch (ValueStorageKind()) { - case FlagValueStorageKind::kAlignedBuffer: - // For this storage kind the default_value_ always points to gen_func - // during initialization. - assert(def_kind == FlagDefaultKind::kGenFunc); - (*default_value_.gen_func)(AlignedBufferValue()); - break; + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { alignas(int64_t) std::array buf{}; if (def_kind == FlagDefaultKind::kGenFunc) { @@ -159,6 +154,12 @@ void FlagImpl::Init() { assert(def_kind != FlagDefaultKind::kDynamicValue); std::memcpy(buf.data(), &default_value_, Sizeof(op_)); } + if (ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit) { + // We presume here the memory layout of FlagValueAndInitBit struct. + uint8_t initialized = 1; + std::memcpy(buf.data() + Sizeof(op_), &initialized, + sizeof(initialized)); + } OneWordValue().store(absl::bit_cast(buf), std::memory_order_release); break; @@ -170,6 +171,12 @@ void FlagImpl::Init() { (*default_value_.gen_func)(AtomicBufferValue()); break; } + case FlagValueStorageKind::kAlignedBuffer: + // For this storage kind the default_value_ always points to gen_func + // during initialization. + assert(def_kind == FlagDefaultKind::kGenFunc); + (*default_value_.gen_func)(AlignedBufferValue()); + break; } seq_lock_.MarkInitialized(); } @@ -226,12 +233,10 @@ std::unique_ptr FlagImpl::MakeInitValue() const { void FlagImpl::StoreValue(const void* src) { switch (ValueStorageKind()) { - case FlagValueStorageKind::kAlignedBuffer: - Copy(op_, src, AlignedBufferValue()); - seq_lock_.IncrementModificationCount(); - break; + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { - int64_t one_word_val = 0; + // Load the current value to avoid setting 'init' bit manualy. + int64_t one_word_val = OneWordValue().load(std::memory_order_acquire); std::memcpy(&one_word_val, src, Sizeof(op_)); OneWordValue().store(one_word_val, std::memory_order_release); seq_lock_.IncrementModificationCount(); @@ -241,6 +246,10 @@ void FlagImpl::StoreValue(const void* src) { seq_lock_.Write(AtomicBufferValue(), src, Sizeof(op_)); break; } + case FlagValueStorageKind::kAlignedBuffer: + Copy(op_, src, AlignedBufferValue()); + seq_lock_.IncrementModificationCount(); + break; } modified_ = true; InvokeCallback(); @@ -280,10 +289,7 @@ std::string FlagImpl::DefaultValue() const { std::string FlagImpl::CurrentValue() const { auto* guard = DataGuard(); // Make sure flag initialized switch (ValueStorageKind()) { - case FlagValueStorageKind::kAlignedBuffer: { - absl::MutexLock l(guard); - return flags_internal::Unparse(op_, AlignedBufferValue()); - } + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { const auto one_word_val = absl::bit_cast>( @@ -296,6 +302,10 @@ std::string FlagImpl::CurrentValue() const { ReadSequenceLockedData(cloned.get()); return flags_internal::Unparse(op_, cloned.get()); } + case FlagValueStorageKind::kAlignedBuffer: { + absl::MutexLock l(guard); + return flags_internal::Unparse(op_, AlignedBufferValue()); + } } return ""; @@ -341,11 +351,7 @@ std::unique_ptr FlagImpl::SaveState() { bool modified = modified_; bool on_command_line = on_command_line_; switch (ValueStorageKind()) { - case FlagValueStorageKind::kAlignedBuffer: { - return absl::make_unique( - *this, flags_internal::Clone(op_, AlignedBufferValue()), modified, - on_command_line, ModificationCount()); - } + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { return absl::make_unique( *this, OneWordValue().load(std::memory_order_acquire), modified, @@ -361,6 +367,11 @@ std::unique_ptr FlagImpl::SaveState() { return absl::make_unique(*this, cloned, modified, on_command_line, ModificationCount()); } + case FlagValueStorageKind::kAlignedBuffer: { + return absl::make_unique( + *this, flags_internal::Clone(op_, AlignedBufferValue()), modified, + on_command_line, ModificationCount()); + } } return nullptr; } @@ -372,13 +383,14 @@ bool FlagImpl::RestoreState(const FlagState& flag_state) { } switch (ValueStorageKind()) { - case FlagValueStorageKind::kAlignedBuffer: - case FlagValueStorageKind::kSequenceLocked: - StoreValue(flag_state.value_.heap_allocated); - break; + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: StoreValue(&flag_state.value_.one_word); break; + case FlagValueStorageKind::kSequenceLocked: + case FlagValueStorageKind::kAlignedBuffer: + StoreValue(flag_state.value_.heap_allocated); + break; } modified_ = flag_state.modified_; @@ -407,7 +419,8 @@ std::atomic* FlagImpl::AtomicBufferValue() const { } std::atomic& FlagImpl::OneWordValue() const { - assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic); + assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic || + ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit); return OffsetValue()->value; } @@ -433,11 +446,7 @@ std::unique_ptr FlagImpl::TryParse( void FlagImpl::Read(void* dst) const { auto* guard = DataGuard(); // Make sure flag initialized switch (ValueStorageKind()) { - case FlagValueStorageKind::kAlignedBuffer: { - absl::MutexLock l(guard); - flags_internal::CopyConstruct(op_, AlignedBufferValue(), dst); - break; - } + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { const int64_t one_word_val = OneWordValue().load(std::memory_order_acquire); @@ -448,9 +457,31 @@ void FlagImpl::Read(void* dst) const { ReadSequenceLockedData(dst); break; } + case FlagValueStorageKind::kAlignedBuffer: { + absl::MutexLock l(guard); + flags_internal::CopyConstruct(op_, AlignedBufferValue(), dst); + break; + } } } +int64_t FlagImpl::ReadOneWord() const { + assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic || + ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit); + auto* guard = DataGuard(); // Make sure flag initialized + (void)guard; + return OneWordValue().load(std::memory_order_acquire); +} + +bool FlagImpl::ReadOneBool() const { + assert(ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit); + auto* guard = DataGuard(); // Make sure flag initialized + (void)guard; + return absl::bit_cast>( + OneWordValue().load(std::memory_order_acquire)) + .value; +} + void FlagImpl::ReadSequenceLockedData(void* dst) const { int size = Sizeof(op_); // Attempt to read using the sequence lock. diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index e6bade0a..8636fadc 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -29,6 +29,7 @@ #include "absl/base/attributes.h" #include "absl/base/call_once.h" +#include "absl/base/casts.h" #include "absl/base/config.h" #include "absl/base/optimization.h" #include "absl/base/thread_annotations.h" @@ -304,49 +305,72 @@ constexpr FlagDefaultArg DefaultArg(char) { constexpr int64_t UninitializedFlagValue() { return 0xababababababababll; } +template +using FlagUseValueAndInitBitStorage = std::integral_constant< + bool, absl::type_traits_internal::is_trivially_copyable::value && + std::is_default_constructible::value && (sizeof(T) < 8)>; + template using FlagUseOneWordStorage = std::integral_constant< bool, absl::type_traits_internal::is_trivially_copyable::value && (sizeof(T) <= 8)>; template -using FlagShouldUseSequenceLock = std::integral_constant< +using FlagUseSequenceLockStorage = std::integral_constant< bool, absl::type_traits_internal::is_trivially_copyable::value && (sizeof(T) > 8)>; enum class FlagValueStorageKind : uint8_t { - kAlignedBuffer = 0, + kValueAndInitBit = 0, kOneWordAtomic = 1, kSequenceLocked = 2, + kAlignedBuffer = 3, }; template static constexpr FlagValueStorageKind StorageKind() { - return FlagUseOneWordStorage::value ? FlagValueStorageKind::kOneWordAtomic - : FlagShouldUseSequenceLock::value + return FlagUseValueAndInitBitStorage::value + ? FlagValueStorageKind::kValueAndInitBit + : FlagUseOneWordStorage::value + ? FlagValueStorageKind::kOneWordAtomic + : FlagUseSequenceLockStorage::value ? FlagValueStorageKind::kSequenceLocked : FlagValueStorageKind::kAlignedBuffer; } struct FlagOneWordValue { - constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {} - + constexpr explicit FlagOneWordValue(int64_t v) : value(v) {} std::atomic value; }; +template +struct alignas(8) FlagValueAndInitBit { + T value; + // Use an int instead of a bool to guarantee that a non-zero value has + // a bit set. + uint8_t init; +}; + template ()> struct FlagValue; template -struct FlagValue { - bool Get(const SequenceLock&, T&) const { return false; } - - alignas(T) char value[sizeof(T)]; +struct FlagValue : FlagOneWordValue { + constexpr FlagValue() : FlagOneWordValue(0) {} + bool Get(const SequenceLock&, T& dst) const { + int64_t storage = value.load(std::memory_order_acquire); + if (ABSL_PREDICT_FALSE(storage == 0)) { + return false; + } + dst = absl::bit_cast>(storage).value; + return true; + } }; template struct FlagValue : FlagOneWordValue { + constexpr FlagValue() : FlagOneWordValue(UninitializedFlagValue()) {} bool Get(const SequenceLock&, T& dst) const { int64_t one_word_val = value.load(std::memory_order_acquire); if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) { @@ -370,6 +394,13 @@ struct FlagValue { std::atomic) std::atomic value_words[kNumWords]; }; +template +struct FlagValue { + bool Get(const SequenceLock&, T&) const { return false; } + + alignas(T) char value[sizeof(T)]; +}; + /////////////////////////////////////////////////////////////////////////////// // Flag callback auxiliary structs. @@ -415,7 +446,27 @@ class FlagImpl final : public CommandLineFlag { data_guard_{} {} // Constant access methods + int64_t ReadOneWord() const ABSL_LOCKS_EXCLUDED(*DataGuard()); + bool ReadOneBool() const ABSL_LOCKS_EXCLUDED(*DataGuard()); void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard()); + void Read(bool* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { + *value = ReadOneBool(); + } + template () == + FlagValueStorageKind::kOneWordAtomic, + int> = 0> + void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { + int64_t v = ReadOneWord(); + std::memcpy(value, static_cast(&v), sizeof(T)); + } + template () == + FlagValueStorageKind::kValueAndInitBit, + int>::type = 0> + void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { + *value = absl::bit_cast>(ReadOneWord()).value; + } // Mutating access methods void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard()); diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index 21915cc1..392b68f1 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel @@ -152,6 +152,7 @@ cc_library( deps = [ "//absl/base:config", "//absl/base:endian", + "//absl/numeric:bits", "//absl/numeric:int128", ], ) diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index 6c79c93a..5916ae3c 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt @@ -126,6 +126,7 @@ absl_cc_library( COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::bits absl::config absl::endian absl::int128 diff --git a/absl/hash/internal/low_level_hash.cc b/absl/hash/internal/low_level_hash.cc index 856bbd9b..6f9cb9c7 100644 --- a/absl/hash/internal/low_level_hash.cc +++ b/absl/hash/internal/low_level_hash.cc @@ -15,6 +15,7 @@ #include "absl/hash/internal/low_level_hash.h" #include "absl/base/internal/unaligned_access.h" +#include "absl/numeric/bits.h" #include "absl/numeric/int128.h" namespace absl { @@ -22,9 +23,20 @@ ABSL_NAMESPACE_BEGIN namespace hash_internal { static uint64_t Mix(uint64_t v0, uint64_t v1) { +#if !defined(__aarch64__) + // The default bit-mixer uses 64x64->128-bit multiplication. absl::uint128 p = v0; p *= v1; return absl::Uint128Low64(p) ^ absl::Uint128High64(p); +#else + // The default bit-mixer above would perform poorly on some ARM microarchs, + // where calculating a 128-bit product requires a sequence of two + // instructions with a high combined latency and poor throughput. + // Instead, we mix bits using only 64-bit arithmetic, which is faster. + uint64_t p = v0 ^ absl::rotl(v1, 40); + p *= v1 ^ absl::rotl(v0, 39); + return p ^ (p >> 11); +#endif } uint64_t LowLevelHash(const void* data, size_t len, uint64_t seed, diff --git a/absl/hash/internal/low_level_hash_test.cc b/absl/hash/internal/low_level_hash_test.cc index 0ef50236..cf22dc3c 100644 --- a/absl/hash/internal/low_level_hash_test.cc +++ b/absl/hash/internal/low_level_hash_test.cc @@ -14,473 +14,519 @@ #include "absl/hash/internal/low_level_hash.h" -#include "absl/strings/escaping.h" +#include + #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/strings/escaping.h" + +#define UPDATE_GOLDEN 0 namespace { -static const uint64_t kCurrentSeed = 0; static const uint64_t kSalt[5] = {0xa0761d6478bd642f, 0xe7037ed1a0b428dbl, 0x8ebc6af09c88c6e3, 0x589965cc75374cc3l, 0x1d8e4e27c47d124f}; -// Note: We don't account for endianness, so the values here are only correct if -// you're also running on a little endian platform. - -TEST(LowLevelHashTest, EmptyString) { - const std::string s = ""; - EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), - kCurrentSeed, kSalt), - 4808886099364463827); -} - -TEST(LowLevelHashTest, Spaces) { - const std::string s = " "; - EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), - kCurrentSeed, kSalt), - 1686201463024549249); -} - -TEST(LowLevelHashTest, RepeatingString) { - const std::string s = "aaaa"; - EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), - kCurrentSeed, kSalt), - 6646112255271966632); -} - -TEST(LowLevelHashTest, HexString) { - const std::string small = "\x01\x02\x03"; - const std::string med = "\x01\x02\x03\x04"; - - EXPECT_EQ(absl::hash_internal::LowLevelHash(small.c_str(), small.length(), - kCurrentSeed, kSalt), - 11989428023081740911ULL); - EXPECT_EQ(absl::hash_internal::LowLevelHash(med.c_str(), med.length(), - kCurrentSeed, kSalt), - 9765997711188871556ULL); -} - -TEST(LowLevelHashTest, Words) { - const std::string s = "third_party|wyhash|64"; - EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), - kCurrentSeed, kSalt), - 3702018632387611330); -} - -TEST(LowLevelHashTest, LongString) { - const std::string s = - "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz" - "0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOp" - "QrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEf" - "GhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz012345" - "6789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789"; - - EXPECT_EQ(absl::hash_internal::LowLevelHash(s.c_str(), s.length(), - kCurrentSeed, kSalt), - 9245411362605796064ULL); -} - -TEST(LowLevelHashTest, BigReference) { - struct ExpectedResult { +TEST(LowLevelHashTest, VerifyGolden) { + constexpr size_t kNumGoldenOutputs = 134; + static struct { absl::string_view base64_data; uint64_t seed; - uint64_t hash; - } expected_results[] = { - {"", uint64_t{0xec42b7ab404b8acb}, uint64_t{0xe5a40d39ab796423}}, - {"Zw==", uint64_t{0xeeee074043a3ee0f}, uint64_t{0xa6564b468248c683}}, - {"xmk=", uint64_t{0x857902089c393de}, uint64_t{0xef192f401b116e1c}}, - {"c1H/", uint64_t{0x993df040024ca3af}, uint64_t{0xbe8dc0c54617639d}}, - {"SuwpzQ==", uint64_t{0xc4e4c2acea740e96}, uint64_t{0x93d7f665b5521c8e}}, - {"uqvy++M=", uint64_t{0x6a214b3db872d0cf}, uint64_t{0x646d70bb42445f28}}, - {"RnzCVPgb", uint64_t{0x44343db6a89dba4d}, uint64_t{0x96a7b1e3cc9bd426}}, - {"6OeNdlouYw==", uint64_t{0x77b5d6d1ae1dd483}, - uint64_t{0x76020289ab0790c4}}, - {"M5/JmmYyDbc=", uint64_t{0x89ab8ecb44d221f1}, - uint64_t{0x39f842e4133b9b44}}, - {"MVijWiVdBRdY", uint64_t{0x60244b17577ca81b}, - uint64_t{0x2b8d7047be4bcaab}}, - {"6V7Uq7LNxpu0VA==", uint64_t{0x59a08dcee0717067}, - uint64_t{0x99628abef6716a97}}, - {"EQ6CdEEhPdyHcOk=", uint64_t{0xf5f20db3ade57396}, - uint64_t{0x4432e02ba42b2740}}, - {"PqFB4fxnPgF+l+rc", uint64_t{0xbf8dee0751ad3efb}, - uint64_t{0x74d810efcad7918a}}, - {"a5aPOFwq7LA7+zKvPA==", uint64_t{0x6b7a06b268d63e30}, - uint64_t{0x88c84e986002507f}}, - {"VOwY21wCGv5D+/qqOvs=", uint64_t{0xb8c37f0ae0f54c82}, - uint64_t{0x4f99acf193cf39b9}}, - {"KdHmBTx8lHXYvmGJ+Vy7", uint64_t{0x9fcbed0c38e50eef}, - uint64_t{0xd90e7a3655891e37}}, - {"qJkPlbHr8bMF7/cA6aE65Q==", uint64_t{0x2af4bade1d8e3a1d}, - uint64_t{0x3bb378b1d4df8fcf}}, - {"ygvL0EhHZL0fIx6oHHtkxRQ=", uint64_t{0x714e3aa912da2f2c}, - uint64_t{0xf78e94045c052d47}}, - {"c1rFXkt5YztwZCQRngncqtSs", uint64_t{0xf5ee75e3cbb82c1c}, - uint64_t{0x26da0b2130da6b40}}, - {"8hsQrzszzeNQSEcVXLtvIhm6mw==", uint64_t{0x620e7007321b93b9}, - uint64_t{0x30b4d426af8c6986}}, - {"ffUL4RocfyP4KfikGxO1yk7omDI=", uint64_t{0xc08528cac2e551fc}, - uint64_t{0x5413b4aaf3baaeae}}, - {"OOB5TT00vF9Od/rLbAWshiErqhpV", uint64_t{0x6a1debf9cc3ad39}, - uint64_t{0x756ab265370a1597}}, - {"or5wtXM7BFzTNpSzr+Lw5J5PMhVJ/Q==", uint64_t{0x7e0a3c88111fc226}, - uint64_t{0xdaf5f4b7d09814fb}}, - {"gk6pCHDUsoopVEiaCrzVDhioRKxb844=", uint64_t{0x1301fef15df39edb}, - uint64_t{0x8f874ae37742b75e}}, - {"TNctmwlC5QbEM6/No4R/La3UdkfeMhzs", uint64_t{0x64e181f3d5817ab}, - uint64_t{0x8fecd03956121ce8}}, - {"SsQw9iAjhWz7sgcE9OwLuSC6hsM+BfHs2Q==", uint64_t{0xafafc44961078ecb}, - uint64_t{0x229c292ea7a08285}}, - {"ZzO3mVCj4xTT2TT3XqDyEKj2BZQBvrS8RHg=", uint64_t{0x4f7bb45549250094}, - uint64_t{0xbb4bf0692d14bae}}, - {"+klp5iPQGtppan5MflEls0iEUzqU+zGZkDJX", uint64_t{0xa30061abaa2818c}, - uint64_t{0x207b24ca3bdac1db}}, - {"RO6bvOnlJc8I9eniXlNgqtKy0IX6VNg16NRmgg==", uint64_t{0xd902ee3e44a5705f}, - uint64_t{0x64f6cd6745d3825b}}, - {"ZJjZqId1ZXBaij9igClE3nyliU5XWdNRrayGlYA=", uint64_t{0x316d36da516f583}, - uint64_t{0xa2b2e1656b58df1e}}, - {"7BfkhfGMDGbxfMB8uyL85GbaYQtjr2K8g7RpLzr/", uint64_t{0x402d83f9f834f616}, - uint64_t{0xd01d30d9ee7a148}}, + } cases[] = { + {"", uint64_t{0xec42b7ab404b8acb}}, + {"ICAg", uint64_t{0}}, + {"YWFhYQ==", uint64_t{0}}, + {"AQID", uint64_t{0}}, + {"AQIDBA==", uint64_t{0}}, + {"dGhpcmRfcGFydHl8d3loYXNofDY0", uint64_t{0}}, + {"Zw==", uint64_t{0xeeee074043a3ee0f}}, + {"xmk=", uint64_t{0x857902089c393de}}, + {"c1H/", uint64_t{0x993df040024ca3af}}, + {"SuwpzQ==", uint64_t{0xc4e4c2acea740e96}}, + {"uqvy++M=", uint64_t{0x6a214b3db872d0cf}}, + {"RnzCVPgb", uint64_t{0x44343db6a89dba4d}}, + {"6OeNdlouYw==", uint64_t{0x77b5d6d1ae1dd483}}, + {"M5/JmmYyDbc=", uint64_t{0x89ab8ecb44d221f1}}, + {"MVijWiVdBRdY", uint64_t{0x60244b17577ca81b}}, + {"6V7Uq7LNxpu0VA==", uint64_t{0x59a08dcee0717067}}, + {"EQ6CdEEhPdyHcOk=", uint64_t{0xf5f20db3ade57396}}, + {"PqFB4fxnPgF+l+rc", uint64_t{0xbf8dee0751ad3efb}}, + {"a5aPOFwq7LA7+zKvPA==", uint64_t{0x6b7a06b268d63e30}}, + {"VOwY21wCGv5D+/qqOvs=", uint64_t{0xb8c37f0ae0f54c82}}, + {"KdHmBTx8lHXYvmGJ+Vy7", uint64_t{0x9fcbed0c38e50eef}}, + {"qJkPlbHr8bMF7/cA6aE65Q==", uint64_t{0x2af4bade1d8e3a1d}}, + {"ygvL0EhHZL0fIx6oHHtkxRQ=", uint64_t{0x714e3aa912da2f2c}}, + {"c1rFXkt5YztwZCQRngncqtSs", uint64_t{0xf5ee75e3cbb82c1c}}, + {"8hsQrzszzeNQSEcVXLtvIhm6mw==", uint64_t{0x620e7007321b93b9}}, + {"ffUL4RocfyP4KfikGxO1yk7omDI=", uint64_t{0xc08528cac2e551fc}}, + {"OOB5TT00vF9Od/rLbAWshiErqhpV", uint64_t{0x6a1debf9cc3ad39}}, + {"or5wtXM7BFzTNpSzr+Lw5J5PMhVJ/Q==", uint64_t{0x7e0a3c88111fc226}}, + {"gk6pCHDUsoopVEiaCrzVDhioRKxb844=", uint64_t{0x1301fef15df39edb}}, + {"TNctmwlC5QbEM6/No4R/La3UdkfeMhzs", uint64_t{0x64e181f3d5817ab}}, + {"SsQw9iAjhWz7sgcE9OwLuSC6hsM+BfHs2Q==", uint64_t{0xafafc44961078ecb}}, + {"ZzO3mVCj4xTT2TT3XqDyEKj2BZQBvrS8RHg=", uint64_t{0x4f7bb45549250094}}, + {"+klp5iPQGtppan5MflEls0iEUzqU+zGZkDJX", uint64_t{0xa30061abaa2818c}}, + {"RO6bvOnlJc8I9eniXlNgqtKy0IX6VNg16NRmgg==", + uint64_t{0xd902ee3e44a5705f}}, + {"ZJjZqId1ZXBaij9igClE3nyliU5XWdNRrayGlYA=", uint64_t{0x316d36da516f583}}, + {"7BfkhfGMDGbxfMB8uyL85GbaYQtjr2K8g7RpLzr/", + uint64_t{0x402d83f9f834f616}}, {"rycWk6wHH7htETQtje9PidS2YzXBx+Qkg2fY7ZYS7A==", - uint64_t{0x9c604164c016b72c}, uint64_t{0x1cb4cd00ab804e3b}}, + uint64_t{0x9c604164c016b72c}}, {"RTkC2OUK+J13CdGllsH0H5WqgspsSa6QzRZouqx6pvI=", - uint64_t{0x3f4507e01f9e73ba}, uint64_t{0x4697f2637fd90999}}, + uint64_t{0x3f4507e01f9e73ba}}, {"tKjKmbLCNyrLCM9hycOAXm4DKNpM12oZ7dLTmUx5iwAi", - uint64_t{0xc3fe0d5be8d2c7c7}, uint64_t{0x8383a756b5688c07}}, + uint64_t{0xc3fe0d5be8d2c7c7}}, {"VprUGNH+5NnNRaORxgH/ySrZFQFDL+4VAodhfBNinmn8cg==", - uint64_t{0x531858a40bfa7ea1}, uint64_t{0x695c29cb3696a975}}, + uint64_t{0x531858a40bfa7ea1}}, {"gc1xZaY+q0nPcUvOOnWnT3bqfmT/geth/f7Dm2e/DemMfk4=", - uint64_t{0x86689478a7a7e8fa}, uint64_t{0xda2e5a5a5e971521}}, + uint64_t{0x86689478a7a7e8fa}}, {"Mr35fIxqx1ukPAL0su1yFuzzAU3wABCLZ8+ZUFsXn47UmAph", - uint64_t{0x4ec948b8e7f27288}, uint64_t{0x7935d4befa056b2b}}, + uint64_t{0x4ec948b8e7f27288}}, {"A9G8pw2+m7+rDtWYAdbl8tb2fT7FFo4hLi2vAsa5Y8mKH3CX3g==", - uint64_t{0xce46c7213c10032}, uint64_t{0x38dd541ca95420fe}}, + uint64_t{0xce46c7213c10032}}, {"DFaJGishGwEHDdj9ixbCoaTjz9KS0phLNWHVVdFsM93CvPft3hM=", - uint64_t{0xf63e96ee6f32a8b6}, uint64_t{0xcc06c7a4963f967f}}, + uint64_t{0xf63e96ee6f32a8b6}}, {"7+Ugx+Kr3aRNgYgcUxru62YkTDt5Hqis+2po81hGBkcrJg4N0uuy", - uint64_t{0x1cfe85e65fc5225}, uint64_t{0xbf0f6f66e232fb20}}, + uint64_t{0x1cfe85e65fc5225}}, {"H2w6O8BUKqu6Tvj2xxaecxEI2wRgIgqnTTG1WwOgDSINR13Nm4d4Vg==", - uint64_t{0x45c474f1cee1d2e8}, uint64_t{0xf7efb32d373fe71a}}, + uint64_t{0x45c474f1cee1d2e8}}, {"1XBMnIbqD5jy65xTDaf6WtiwtdtQwv1dCVoqpeKj+7cTR1SaMWMyI04=", - uint64_t{0x6e024e14015f329c}, uint64_t{0xe2e64634b1c12660}}, + uint64_t{0x6e024e14015f329c}}, {"znZbdXG2TSFrKHEuJc83gPncYpzXGbAebUpP0XxzH0rpe8BaMQ17nDbt", - uint64_t{0x760c40502103ae1c}, uint64_t{0x285b8fd1638e306d}}, + uint64_t{0x760c40502103ae1c}}, {"ylu8Atu13j1StlcC1MRMJJXIl7USgDDS22HgVv0WQ8hx/8pNtaiKB17hCQ==", - uint64_t{0x17fd05c3c560c320}, uint64_t{0x658e8a4e3b714d6c}}, + uint64_t{0x17fd05c3c560c320}}, {"M6ZVVzsd7vAvbiACSYHioH/440dp4xG2mLlBnxgiqEvI/aIEGpD0Sf4VS0g=", - uint64_t{0x8b34200a6f8e90d9}, uint64_t{0xf391fb968e0eb398}}, + uint64_t{0x8b34200a6f8e90d9}}, {"li3oFSXLXI+ubUVGJ4blP6mNinGKLHWkvGruun85AhVn6iuMtocbZPVhqxzn", - uint64_t{0x6be89e50818bdf69}, uint64_t{0x744a9ea0cc144bf2}}, + uint64_t{0x6be89e50818bdf69}}, {"kFuQHuUCqBF3Tc3hO4dgdIp223ShaCoog48d5Do5zMqUXOh5XpGK1t5XtxnfGA==", - uint64_t{0xfb389773315b47d8}, uint64_t{0x12636f2be11012f1}}, + uint64_t{0xfb389773315b47d8}}, {"jWmOad0v0QhXVJd1OdGuBZtDYYS8wBVHlvOeTQx9ZZnm8wLEItPMeihj72E0nWY=", - uint64_t{0x4f2512a23f61efee}, uint64_t{0x29c57de825948f80}}, + uint64_t{0x4f2512a23f61efee}}, {"z+DHU52HaOQdW4JrZwDQAebEA6rm13Zg/9lPYA3txt3NjTBqFZlOMvTRnVzRbl23", - uint64_t{0x59ccd92fc16c6fda}, uint64_t{0x58c6f99ab0d1c021}}, + uint64_t{0x59ccd92fc16c6fda}}, {"MmBiGDfYeTayyJa/tVycg+rN7f9mPDFaDc+23j0TlW9094er0ADigsl4QX7V3gG/qw==", - uint64_t{0x25c5a7f5bd330919}, uint64_t{0x13e7b5a7b82fe3bb}}, + uint64_t{0x25c5a7f5bd330919}}, {"774RK+9rOL4iFvs1q2qpo/JVc/I39buvNjqEFDtDvyoB0FXxPI2vXqOrk08VPfIHkmU=", - uint64_t{0x51df4174d34c97d7}, uint64_t{0x10fbc87901e02b63}}, + uint64_t{0x51df4174d34c97d7}}, {"+slatXiQ7/2lK0BkVUI1qzNxOOLP3I1iK6OfHaoxgqT63FpzbElwEXSwdsryq3UlHK0I", - uint64_t{0x80ce6d76f89cb57}, uint64_t{0xa24c9184901b748b}}, + uint64_t{0x80ce6d76f89cb57}}, {"64mVTbQ47dHjHlOHGS/hjJwr/" "K2frCNpn87exOqMzNUVYiPKmhCbfS7vBUce5tO6Ec9osQ==", - uint64_t{0x20961c911965f684}, uint64_t{0xcac4fd4c5080e581}}, + uint64_t{0x20961c911965f684}}, {"fIsaG1r530SFrBqaDj1kqE0AJnvvK8MNEZbII2Yw1OK77v0V59xabIh0B5axaz/" "+a2V5WpA=", - uint64_t{0x4e5b926ec83868e7}, uint64_t{0xc38bdb7483ba68e1}}, + uint64_t{0x4e5b926ec83868e7}}, {"PGih0zDEOWCYGxuHGDFu9Ivbff/" "iE7BNUq65tycTR2R76TerrXALRosnzaNYO5fjFhTi+CiS", - uint64_t{0x3927b30b922eecef}, uint64_t{0xdb2a8069b2ceaffa}}, + uint64_t{0x3927b30b922eecef}}, {"RnpA/" "zJnEnnLjmICORByRVb9bCOgxF44p3VMiW10G7PvW7IhwsWajlP9kIwNA9FjAD2GoQHk2Q=" "=", - uint64_t{0xbd0291284a49b61c}, uint64_t{0xdf9fe91d0d1c7887}}, + uint64_t{0xbd0291284a49b61c}}, {"qFklMceaTHqJpy2qavJE+EVBiNFOi6OxjOA3LeIcBop1K7w8xQi3TrDk+" "BrWPRIbfprszSaPfrI=", - uint64_t{0x73a77c575bcc956}, uint64_t{0xe83f49e96e2e6a08}}, + uint64_t{0x73a77c575bcc956}}, {"cLbfUtLl3EcQmITWoTskUR8da/VafRDYF/ylPYwk7/" "zazk6ssyrzxMN3mmSyvrXR2yDGNZ3WDrTT", - uint64_t{0x766a0e2ade6d09a6}, uint64_t{0xc69e61b62ca2b62}}, + uint64_t{0x766a0e2ade6d09a6}}, {"s/" "Jf1+" "FbsbCpXWPTUSeWyMH6e4CvTFvPE5Fs6Z8hvFITGyr0dtukHzkI84oviVLxhM1xMxrMAy1db" "w==", - uint64_t{0x2599f4f905115869}, uint64_t{0xb4a4f3f85f8298fe}}, + uint64_t{0x2599f4f905115869}}, {"FvyQ00+j7nmYZVQ8hI1Edxd0AWplhTfWuFGiu34AK5X8u2hLX1bE97sZM0CmeLe+" "7LgoUT1fJ/axybE=", - uint64_t{0xd8256e5444d21e53}, uint64_t{0x167a1b39e1e95f41}}, + uint64_t{0xd8256e5444d21e53}}, {"L8ncxMaYLBH3g9buPu8hfpWZNlOF7nvWLNv9IozH07uQsIBWSKxoPy8+" "LW4tTuzC6CIWbRGRRD1sQV/4", - uint64_t{0xf664a91333fb8dfd}, uint64_t{0xf8a2a5649855ee41}}, + uint64_t{0xf664a91333fb8dfd}}, {"CDK0meI07yrgV2kQlZZ+" "wuVqhc2NmzqeLH7bmcA6kchsRWFPeVF5Wqjjaj556ABeUoUr3yBmfU3kWOakkg==", - uint64_t{0x9625b859be372cd1}, uint64_t{0x27992565b595c498}}, + uint64_t{0x9625b859be372cd1}}, {"d23/vc5ONh/" "HkMiq+gYk4gaCNYyuFKwUkvn46t+dfVcKfBTYykr4kdvAPNXGYLjM4u1YkAEFpJP+" "nX7eOvs=", - uint64_t{0x7b99940782e29898}, uint64_t{0x3e08cca5b71f9346}}, + uint64_t{0x7b99940782e29898}}, {"NUR3SRxBkxTSbtQORJpu/GdR6b/h6sSGfsMj/KFd99ahbh+9r7LSgSGmkGVB/" "mGoT0pnMTQst7Lv2q6QN6Vm", - uint64_t{0x4fe12fa5383b51a8}, uint64_t{0xad406b10c770a6d2}}, + uint64_t{0x4fe12fa5383b51a8}}, {"2BOFlcI3Z0RYDtS9T9Ie9yJoXlOdigpPeeT+CRujb/" "O39Ih5LPC9hP6RQk1kYESGyaLZZi3jtabHs7DiVx/VDg==", - uint64_t{0xe2ccb09ac0f5b4b6}, uint64_t{0xd1713ce6e552bcf2}}, + uint64_t{0xe2ccb09ac0f5b4b6}}, {"FF2HQE1FxEvWBpg6Z9zAMH+Zlqx8S1JD/" "wIlViL6ZDZY63alMDrxB0GJQahmAtjlm26RGLnjW7jmgQ4Ie3I+014=", - uint64_t{0x7d0a37adbd7b753b}, uint64_t{0x753b287194c73ad3}}, + uint64_t{0x7d0a37adbd7b753b}}, {"tHmO7mqVL/PX11nZrz50Hc+M17Poj5lpnqHkEN+4bpMx/" "YGbkrGOaYjoQjgmt1X2QyypK7xClFrjeWrCMdlVYtbW", - uint64_t{0xd3ae96ef9f7185f2}, uint64_t{0x5ae41a95f600af1c}}, + uint64_t{0xd3ae96ef9f7185f2}}, {"/WiHi9IQcxRImsudkA/KOTqGe8/" "gXkhKIHkjddv5S9hi02M049dIK3EUyAEjkjpdGLUs+BN0QzPtZqjIYPOgwsYE9g==", - uint64_t{0x4fb88ea63f79a0d8}, uint64_t{0x4a61163b86a8bb4c}}, + uint64_t{0x4fb88ea63f79a0d8}}, {"qds+1ExSnU11L4fTSDz/QE90g4Jh6ioqSh3KDOTOAo2pQGL1k/" "9CCC7J23YF27dUTzrWsCQA2m4epXoCc3yPHb3xElA=", - uint64_t{0xed564e259bb5ebe9}, uint64_t{0x42eeaa79e760c7e4}}, + uint64_t{0xed564e259bb5ebe9}}, {"8FVYHx40lSQPTHheh08Oq0/" "pGm2OlG8BEf8ezvAxHuGGdgCkqpXIueJBF2mQJhTfDy5NncO8ntS7vaKs7sCNdDaNGOEi", - uint64_t{0x3e3256b60c428000}, uint64_t{0x698df622ef465b0a}}, + uint64_t{0x3e3256b60c428000}}, {"4ZoEIrJtstiCkeew3oRzmyJHVt/pAs2pj0HgHFrBPztbQ10NsQ/" "lM6DM439QVxpznnBSiHMgMQJhER+70l72LqFTO1JiIQ==", - uint64_t{0xfb05bad59ec8705}, uint64_t{0x157583111e1a6026}}, + uint64_t{0xfb05bad59ec8705}}, {"hQPtaYI+wJyxXgwD5n8jGIKFKaFA/" "P83KqCKZfPthnjwdOFysqEOYwAaZuaaiv4cDyi9TyS8hk5cEbNP/jrI7q6pYGBLbsM=", - uint64_t{0xafdc251dbf97b5f8}, uint64_t{0xaa1388f078e793e0}}, + uint64_t{0xafdc251dbf97b5f8}}, {"S4gpMSKzMD7CWPsSfLeYyhSpfWOntyuVZdX1xSBjiGvsspwOZcxNKCRIOqAA0moUfOh3I5+" "juQV4rsqYElMD/gWfDGpsWZKQ", - uint64_t{0x10ec9c92ddb5dcbc}, uint64_t{0xf10d68d0f3309360}}, + uint64_t{0x10ec9c92ddb5dcbc}}, {"oswxop+" "bthuDLT4j0PcoSKby4LhF47ZKg8K17xxHf74UsGCzTBbOz0MM8hQEGlyqDT1iUiAYnaPaUp" "L2mRK0rcIUYA4qLt5uOw==", - uint64_t{0x9a767d5822c7dac4}, uint64_t{0x2af056184457a3de}}, + uint64_t{0x9a767d5822c7dac4}}, {"0II/" "697p+" "BtLSjxj5989OXI004TogEb94VUnDzOVSgMXie72cuYRvTFNIBgtXlKfkiUjeqVpd4a+" "n5bxNOD1TGrjQtzKU5r7obo=", - uint64_t{0xee46254080d6e2db}, uint64_t{0x6d0058e1590b2489}}, + uint64_t{0xee46254080d6e2db}}, {"E84YZW2qipAlMPmctrg7TKlwLZ68l4L+c0xRDUfyyFrA4MAti0q9sHq3TDFviH0Y+" "Kq3tEE5srWFA8LM9oomtmvm5PYxoaarWPLc", - uint64_t{0xbbb669588d8bf398}, uint64_t{0x638f287f68817f12}}, + uint64_t{0xbbb669588d8bf398}}, {"x3pa4HIElyZG0Nj7Vdy9IdJIR4izLmypXw5PCmZB5y68QQ4uRaVVi3UthsoJROvbjDJkP2D" "Q6L/eN8pFeLFzNPKBYzcmuMOb5Ull7w==", - uint64_t{0xdc2afaa529beef44}, uint64_t{0xc46b71fecefd5467}}, + uint64_t{0xdc2afaa529beef44}}, {"jVDKGYIuWOP/" "QKLdd2wi8B2VJA8Wh0c8PwrXJVM8FOGM3voPDVPyDJOU6QsBDPseoR8uuKd19OZ/" "zAvSCB+zlf6upAsBlheUKgCfKww=", - uint64_t{0xf1f67391d45013a8}, uint64_t{0x2c8e94679d964e0a}}, + uint64_t{0xf1f67391d45013a8}}, {"mkquunhmYe1aR2wmUz4vcvLEcKBoe6H+kjUok9VUn2+eTSkWs4oDDtJvNCWtY5efJwg/" "j4PgjRYWtqnrCkhaqJaEvkkOwVfgMIwF3e+d", - uint64_t{0x16fce2b8c65a3429}, uint64_t{0x8612b797ce22503a}}, + uint64_t{0x16fce2b8c65a3429}}, {"fRelvKYonTQ+s+rnnvQw+JzGfFoPixtna0vzcSjiDqX5s2Kg2//" "UGrK+AVCyMUhO98WoB1DDbrsOYSw2QzrcPe0+3ck9sePvb+Q/IRaHbw==", - uint64_t{0xf4b096699f49fe67}, uint64_t{0x59f929babfba7170}}, + uint64_t{0xf4b096699f49fe67}}, {"DUwXFJzagljo44QeJ7/" "6ZKw4QXV18lhkYT2jglMr8WB3CHUU4vdsytvw6AKv42ZcG6fRkZkq9fpnmXy6xG0aO3WPT1" "eHuyFirAlkW+zKtwg=", - uint64_t{0xca584c4bc8198682}, uint64_t{0x9527556923fb49a0}}, + uint64_t{0xca584c4bc8198682}}, {"cYmZCrOOBBongNTr7e4nYn52uQUy2mfe48s50JXx2AZ6cRAt/" "xRHJ5QbEoEJOeOHsJyM4nbzwFm++SlT6gFZZHJpkXJ92JkR86uS/eV1hJUR", - uint64_t{0xed269fc3818b6aad}, uint64_t{0x1039ab644f5e150b}}, + uint64_t{0xed269fc3818b6aad}}, {"EXeHBDfhwzAKFhsMcH9+2RHwV+mJaN01+9oacF6vgm8mCXRd6jeN9U2oAb0of5c5cO4i+" "Vb/LlHZSMI490SnHU0bejhSCC2gsC5d2K30ER3iNA==", - uint64_t{0x33f253cbb8fe66a8}, uint64_t{0x7816c83f3aa05e6d}}, + uint64_t{0x33f253cbb8fe66a8}}, {"FzkzRYoNjkxFhZDso94IHRZaJUP61nFYrh5MwDwv9FNoJ5jyNCY/" "eazPZk+tbmzDyJIGw2h3GxaWZ9bSlsol/vK98SbkMKCQ/wbfrXRLcDzdd/8=", - uint64_t{0xd0b76b2c1523d99c}, uint64_t{0xf51d2f564518c619}}, + uint64_t{0xd0b76b2c1523d99c}}, {"Re4aXISCMlYY/XsX7zkIFR04ta03u4zkL9dVbLXMa/q6hlY/CImVIIYRN3VKP4pnd0AUr/" "ugkyt36JcstAInb4h9rpAGQ7GMVOgBniiMBZ/MGU7H", - uint64_t{0xfd28f0811a2a237f}, uint64_t{0x67d494cff03ac004}}, + uint64_t{0xfd28f0811a2a237f}}, {"ueLyMcqJXX+MhO4UApylCN9WlTQ+" "ltJmItgG7vFUtqs2qNwBMjmAvr5u0sAKd8jpzV0dDPTwchbIeAW5zbtkA2NABJV6hFM48ib" "4/J3A5mseA3cS8w==", - uint64_t{0x6261fb136482e84}, uint64_t{0x2802d636ced1cfbb}}, + uint64_t{0x6261fb136482e84}}, {"6Si7Yi11L+jZMkwaN+GUuzXMrlvEqviEkGOilNq0h8TdQyYKuFXzkYc/" "q74gP3pVCyiwz9KpVGMM9vfnq36riMHRknkmhQutxLZs5fbmOgEO69HglCU=", - uint64_t{0x458efc750bca7c3a}, uint64_t{0xf64e20bad771cb12}}, + uint64_t{0x458efc750bca7c3a}}, {"Q6AbOofGuTJOegPh9Clm/" "9crtUMQqylKrTc1fhfJo1tqvpXxhU4k08kntL1RG7woRnFrVh2UoMrL1kjin+s9CanT+" "y4hHwLqRranl9FjvxfVKm3yvg68", - uint64_t{0xa7e69ff84e5e7c27}, uint64_t{0xb9a6cf84a83e15e}}, + uint64_t{0xa7e69ff84e5e7c27}}, {"ieQEbIPvqY2YfIjHnqfJiO1/MIVRk0RoaG/WWi3kFrfIGiNLCczYoklgaecHMm/" "1sZ96AjO+a5stQfZbJQwS7Sc1ODABEdJKcTsxeW2hbh9A6CFzpowP1A==", - uint64_t{0x3c59bfd0c29efe9e}, uint64_t{0x8da6630319609301}}, + uint64_t{0x3c59bfd0c29efe9e}}, {"zQUv8hFB3zh2GGl3KTvCmnfzE+" "SUgQPVaSVIELFX5H9cE3FuVFGmymkPQZJLAyzC90Cmi8GqYCvPqTuAAB//" "XTJxy4bCcVArgZG9zJXpjowpNBfr3ngWrSE=", - uint64_t{0x10befacc6afd298d}, uint64_t{0x40946a86e2a996f3}}, + uint64_t{0x10befacc6afd298d}}, {"US4hcC1+op5JKGC7eIs8CUgInjKWKlvKQkapulxW262E/" "B2ye79QxOexf188u2mFwwe3WTISJHRZzS61IwljqAWAWoBAqkUnW8SHmIDwHUP31J0p5sGd" "P47L", - uint64_t{0x41d5320b0a38efa7}, uint64_t{0xcab7f5997953fa76}}, + uint64_t{0x41d5320b0a38efa7}}, {"9bHUWFna2LNaGF6fQLlkx1Hkt24nrkLE2CmFdWgTQV3FFbUe747SSqYw6ebpTa07MWSpWRP" "sHesVo2B9tqHbe7eQmqYebPDFnNqrhSdZwFm9arLQVs+7a3Ic6A==", - uint64_t{0x58db1c7450fe17f3}, uint64_t{0x39129ca0e04fc465}}, + uint64_t{0x58db1c7450fe17f3}}, {"Kb3DpHRUPhtyqgs3RuXjzA08jGb59hjKTOeFt1qhoINfYyfTt2buKhD6YVffRCPsgK9SeqZ" "qRPJSyaqsa0ovyq1WnWW8jI/NhvAkZTVHUrX2pC+cD3OPYT05Dag=", - uint64_t{0x6098c055a335b7a6}, uint64_t{0x5238221fd685e1b8}}, + uint64_t{0x6098c055a335b7a6}}, {"gzxyMJIPlU+bJBwhFUCHSofZ/" "319LxqMoqnt3+L6h2U2+ZXJCSsYpE80xmR0Ta77Jq54o92SMH87HV8dGOaCTuAYF+" "lDL42SY1P316Cl0sZTS2ow3ZqwGbcPNs/1", - uint64_t{0x1bbacec67845a801}, uint64_t{0x175130c407dbcaab}}, + uint64_t{0x1bbacec67845a801}}, {"uR7V0TW+FGVMpsifnaBAQ3IGlr1wx5sKd7TChuqRe6OvUXTlD4hKWy8S+" "8yyOw8lQabism19vOQxfmocEOW/" "vzY0pEa87qHrAZy4s9fH2Bltu8vaOIe+agYohhYORQ==", - uint64_t{0xc419cfc7442190}, uint64_t{0x2f20e7536c0b0df}}, + uint64_t{0xc419cfc7442190}}, {"1UR5eoo2aCwhacjZHaCh9bkOsITp6QunUxHQ2SfeHv0imHetzt/" "Z70mhyWZBalv6eAx+YfWKCUib2SHDtz/" "A2dc3hqUWX5VfAV7FQsghPUAtu6IiRatq4YSLpDvKZBQ=", - uint64_t{0xc95e510d94ba270c}, uint64_t{0x2742cb488a04ad56}}, + uint64_t{0xc95e510d94ba270c}}, {"opubR7H63BH7OtY+Avd7QyQ25UZ8kLBdFDsBTwZlY6gA/" "u+x+" "czC9AaZMgmQrUy15DH7YMGsvdXnviTtI4eVI4aF1H9Rl3NXMKZgwFOsdTfdcZeeHVRzBBKX" "8jUfh1il", - uint64_t{0xff1ae05c98089c3f}, uint64_t{0xd6afb593879ff93b}}, + uint64_t{0xff1ae05c98089c3f}}, {"DC0kXcSXtfQ9FbSRwirIn5tgPri0sbzHSa78aDZVDUKCMaBGyFU6BmrulywYX8yzvwprdLs" "oOwTWN2wMjHlPDqrvVHNEjnmufRDblW+nSS+xtKNs3N5xsxXdv6JXDrAB/Q==", - uint64_t{0x90c02b8dceced493}, uint64_t{0xf50ad64caac0ca7f}}, + uint64_t{0x90c02b8dceced493}}, {"BXRBk+3wEP3Lpm1y75wjoz+PgB0AMzLe8tQ1AYU2/" "oqrQB2YMC6W+9QDbcOfkGbeH+b7IBkt/" "gwCMw2HaQsRFEsurXtcQ3YwRuPz5XNaw5NAvrNa67Fm7eRzdE1+hWLKtA8=", - uint64_t{0x9f8a76697ab1aa36}, uint64_t{0x2ade95c4261364ae}}, + uint64_t{0x9f8a76697ab1aa36}}, {"RRBSvEGYnzR9E45Aps/+WSnpCo/X7gJLO4DRnUqFrJCV/kzWlusLE/" "6ZU6RoUf2ROwcgEvUiXTGjLs7ts3t9SXnJHxC1KiOzxHdYLMhVvgNd3hVSAXODpKFSkVXND" "55G2L1W", - uint64_t{0x6ba1bf3d811a531d}, uint64_t{0x5c4f3299faacd07a}}, + uint64_t{0x6ba1bf3d811a531d}}, {"jeh6Qazxmdi57pa9S3XSnnZFIRrnc6s8QLrah5OX3SB/V2ErSPoEAumavzQPkdKF1/" "SfvmdL+qgF1C+Yawy562QaFqwVGq7+tW0yxP8FStb56ZRgNI4IOmI30s1Ei7iops9Uuw==", - uint64_t{0x6a418974109c67b4}, uint64_t{0xfffe3bff0ae5e9bc}}, + uint64_t{0x6a418974109c67b4}}, {"6QO5nnDrY2/" "wrUXpltlKy2dSBcmK15fOY092CR7KxAjNfaY+" "aAmtWbbzQk3MjBg03x39afSUN1fkrWACdyQKRaGxgwq6MGNxI6W+8DLWJBHzIXrntrE/" "ml6fnNXEpxplWJ1vEs4=", - uint64_t{0x8472f1c2b3d230a3}, uint64_t{0x1db785c0005166e4}}, + uint64_t{0x8472f1c2b3d230a3}}, {"0oPxeEHhqhcFuwonNfLd5jF3RNATGZS6NPoS0WklnzyokbTqcl4BeBkMn07+fDQv83j/" "BpGUwcWO05f3+DYzocfnizpFjLJemFGsls3gxcBYxcbqWYev51tG3lN9EvRE+X9+Pwww", - uint64_t{0x5e06068f884e73a7}, uint64_t{0xea000d962ad18418}}, + uint64_t{0x5e06068f884e73a7}}, {"naSBSjtOKgAOg8XVbR5cHAW3Y+QL4Pb/JO9/" "oy6L08wvVRZqo0BrssMwhzBP401Um7A4ppAupbQeJFdMrysY34AuSSNvtNUy5VxjNECwiNt" "gwYHw7yakDUv8WvonctmnoSPKENegQg==", - uint64_t{0x55290b1a8f170f59}, uint64_t{0xe42aef38359362d9}}, + uint64_t{0x55290b1a8f170f59}}, {"vPyl8DxVeRe1OpilKb9KNwpGkQRtA94UpAHetNh+" "95V7nIW38v7PpzhnTWIml5kw3So1Si0TXtIUPIbsu32BNhoH7QwFvLM+" "JACgSpc5e3RjsL6Qwxxi11npwxRmRUqATDeMUfRAjxg=", - uint64_t{0x5501cfd83dfe706a}, uint64_t{0xc8e95657348a3891}}, + uint64_t{0x5501cfd83dfe706a}}, {"QC9i2GjdTMuNC1xQJ74ngKfrlA4w3o58FhvNCltdIpuMhHP1YsDA78scQPLbZ3OCUgeQguY" "f/vw6zAaVKSgwtaykqg5ka/4vhz4hYqWU5ficdXqClHl+zkWEY26slCNYOM5nnDlly8Cj", - uint64_t{0xe43ed13d13a66990}, uint64_t{0xc162eca864f238c6}}, + uint64_t{0xe43ed13d13a66990}}, {"7CNIgQhAHX27nxI0HeB5oUTnTdgKpRDYDKwRcXfSFGP1XeT9nQF6WKCMjL1tBV6x7KuJ91G" "Zz11F4c+8s+MfqEAEpd4FHzamrMNjGcjCyrVtU6y+7HscMVzr7Q/" "ODLcPEFztFnwjvCjmHw==", - uint64_t{0xdf43bc375cf5283f}, uint64_t{0xbe1fb373e20579ad}}, + uint64_t{0xdf43bc375cf5283f}}, {"Qa/hC2RPXhANSospe+gUaPfjdK/yhQvfm4cCV6/pdvCYWPv8p1kMtKOX3h5/" "8oZ31fsmx4Axphu5qXJokuhZKkBUJueuMpxRyXpwSWz2wELx5glxF7CM0Fn+" "OevnkhUn5jsPlG2r5jYlVn8=", - uint64_t{0x8112b806d288d7b5}, uint64_t{0x628a1d4f40aa6ffd}}, + uint64_t{0x8112b806d288d7b5}}, {"kUw/0z4l3a89jTwN5jpG0SHY5km/" "IVhTjgM5xCiPRLncg40aqWrJ5vcF891AOq5hEpSq0bUCJUMFXgct7kvnys905HjerV7Vs1G" "y84tgVJ70/2+pAZTsB/PzNOE/G6sOj4+GbTzkQu819OLB", - uint64_t{0xd52a18abb001cb46}, uint64_t{0xa87bdb7456340f90}}, + uint64_t{0xd52a18abb001cb46}}, {"VDdfSDbO8Tdj3T5W0XM3EI7iHh5xpIutiM6dvcJ/fhe23V/srFEkDy5iZf/" "VnA9kfi2C79ENnFnbOReeuZW1b3MUXB9lgC6U4pOTuC+" "jHK3Qnpyiqzj7h3ISJSuo2pob7vY6VHZo6Fn7exEqHg==", - uint64_t{0xe12b76a2433a1236}, uint64_t{0x5960ef3ba982c801}}, + uint64_t{0xe12b76a2433a1236}}, {"Ldfvy3ORdquM/R2fIkhH/ONi69mcP1AEJ6n/" "oropwecAsLJzQSgezSY8bEiEs0VnFTBBsW+RtZY6tDj03fnb3amNUOq1b7jbqyQkL9hpl+" "2Z2J8IaVSeownWl+bQcsR5/xRktIMckC5AtF4YHfU=", - uint64_t{0x175bf7319cf1fa00}, uint64_t{0x5026586df9a431ec}}, + uint64_t{0x175bf7319cf1fa00}}, {"BrbNpb42+" "VzZAjJw6QLirXzhweCVRfwlczzZ0VX2xluskwBqyfnGovz5EuX79JJ31VNXa5hTkAyQat3l" "YKRADTdAdwE5PqM1N7YaMqqsqoAAAeuYVXuk5eWCykYmClNdSspegwgCuT+403JigBzi", - uint64_t{0xd63d57b3f67525ae}, uint64_t{0xfe4b8a20fdf0840b}}, + uint64_t{0xd63d57b3f67525ae}}, {"gB3NGHJJvVcuPyF0ZSvHwnWSIfmaI7La24VMPQVoIIWF7Z74NltPZZpx2f+cocESM+" "ILzQW9p+BC8x5IWz7N4Str2WLGKMdgmaBfNkEhSHQDU0IJEOnpUt0HmjhFaBlx0/" "LTmhua+rQ6Wup8ezLwfg==", - uint64_t{0x933faea858832b73}, uint64_t{0xdcb761867da7072f}}, + uint64_t{0x933faea858832b73}}, {"hTKHlRxx6Pl4gjG+6ksvvj0CWFicUg3WrPdSJypDpq91LUWRni2KF6+" "81ZoHBFhEBrCdogKqeK+hy9bLDnx7g6rAFUjtn1+cWzQ2YjiOpz4+" "ROBB7lnwjyTGWzJD1rXtlso1g2qVH8XJVigC5M9AIxM=", - uint64_t{0x53d061e5f8e7c04f}, uint64_t{0xc10d4653667275b7}}, + uint64_t{0x53d061e5f8e7c04f}}, {"IWQBelSQnhrr0F3BhUpXUIDauhX6f95Qp+A0diFXiUK7irwPG1oqBiqHyK/SH/" "9S+" "rln9DlFROAmeFdH0OCJi2tFm4afxYzJTFR4HnR4cG4x12JqHaZLQx6iiu6CE3rtWBVz99oA" "wCZUOEXIsLU24o2Y", - uint64_t{0xdb4124556dd515e0}, uint64_t{0x727720deec13110b}}, + uint64_t{0xdb4124556dd515e0}}, {"TKo+l+" "1dOXdLvIrFqeLaHdm0HZnbcdEgOoLVcGRiCbAMR0j5pIFw8D36tefckAS1RCFOH5IgP8yiF" "T0Gd0a2hI3+" "fTKA7iK96NekxWeoeqzJyctc6QsoiyBlkZerRxs5RplrxoeNg29kKDTM0K94mnhD9g==", - uint64_t{0x4fb31a0dd681ee71}, uint64_t{0x710b009662858dc9}}, + uint64_t{0x4fb31a0dd681ee71}}, {"YU4e7G6EfQYvxCFoCrrT0EFgVLHFfOWRTJQJ5gxM3G2b+" "1kJf9YPrpsxF6Xr6nYtS8reEEbDoZJYqnlk9lXSkVArm88Cqn6d25VCx3+" "49MqC0trIlXtb7SXUUhwpJK16T0hJUfPH7s5cMZXc6YmmbFuBNPE=", - uint64_t{0x27cc72eefa138e4c}, uint64_t{0xfbf8f7a3ecac1eb7}}, + uint64_t{0x27cc72eefa138e4c}}, {"/I/" "eImMwPo1U6wekNFD1Jxjk9XQVi1D+" "FPdqcHifYXQuP5aScNQfxMAmaPR2XhuOQhADV5tTVbBKwCDCX4E3jcDNHzCiPvViZF1W27t" "xaf2BbFQdwKrNCmrtzcluBFYu0XZfc7RU1RmxK/RtnF1qHsq/O4pp", - uint64_t{0x44bc2dfba4bd3ced}, uint64_t{0xb6fc4fcd0722e3df}}, + uint64_t{0x44bc2dfba4bd3ced}}, {"CJTT9WGcY2XykTdo8KodRIA29qsqY0iHzWZRjKHb9alwyJ7RZAE3V5Juv4MY3MeYEr1EPCC" "MxO7yFXqT8XA8YTjaMp3bafRt17Pw8JC4iKJ1zN+WWKOESrj+" "3aluGQqn8z1EzqY4PH7rLG575PYeWsP98BugdA==", - uint64_t{0x242da1e3a439bed8}, uint64_t{0x7cb86dcc55104aac}}, + uint64_t{0x242da1e3a439bed8}}, {"ZlhyQwLhXQyIUEnMH/" "AEW27vh9xrbNKJxpWGtrEmKhd+nFqAfbeNBQjW0SfG1YI0xQkQMHXjuTt4P/" "EpZRtA47ibZDVS8TtaxwyBjuIDwqcN09eCtpC+Ls+" "vWDTLmBeDM3u4hmzz4DQAYsLiZYSJcldg9Q3wszw=", - uint64_t{0xdc559c746e35c139}, uint64_t{0x19e71e9b45c3a51e}}, + uint64_t{0xdc559c746e35c139}}, {"v2KU8y0sCrBghmnm8lzGJlwo6D6ObccAxCf10heoDtYLosk4ztTpLlpSFEyu23MLA1tJkcg" "Rko04h19QMG0mOw/" "wc93EXAweriBqXfvdaP85sZABwiKO+6rtS9pacRVpYYhHJeVTQ5NzrvBvi1huxAr+" "xswhVMfL", - uint64_t{0xd0b0350275b9989}, uint64_t{0x51de38573c2bea48}}, + uint64_t{0xd0b0350275b9989}}, {"QhKlnIS6BuVCTQsnoE67E/" "yrgogE8EwO7xLaEGei26m0gEU4OksefJgppDh3X0x0Cs78Dr9IHK5b977CmZlrTRmwhlP8p" "M+UzXPNRNIZuN3ntOum/QhUWP8SGpirheXENWsXMQ/" "nxtxakyEtrNkKk471Oov9juP8oQ==", - uint64_t{0xb04489e41d17730c}, uint64_t{0xa73ab6996d6df158}}, + uint64_t{0xb04489e41d17730c}}, {"/ZRMgnoRt+Uo6fUPr9FqQvKX7syhgVqWu+" "WUSsiQ68UlN0efSP6Eced5gJZL6tg9gcYJIkhjuQNITU0Q3TjVAnAcobgbJikCn6qZ6pRxK" "BY4MTiAlfGD3T7R7hwJwx554MAy++Zb/YUFlnCaCJiwQMnowF7aQzwYFCo=", - uint64_t{0x2217285eb4572156}, uint64_t{0x55ef2b8c930817b2}}, + uint64_t{0x2217285eb4572156}}, {"NB7tU5fNE8nI+SXGfipc7sRkhnSkUF1krjeo6k+8FITaAtdyz+" "o7mONgXmGLulBPH9bEwyYhKNVY0L+njNQrZ9YC2aXsFD3PdZsxAFaBT3VXEzh+" "NGBTjDASNL3mXyS8Yv1iThGfHoY7T4aR0NYGJ+k+pR6f+KrPC96M", - uint64_t{0x12c2e8e68aede73b}, uint64_t{0xb2850bf5fae87157}}, + uint64_t{0x12c2e8e68aede73b}}, {"8T6wrqCtEO6/rwxF6lvMeyuigVOLwPipX/FULvwyu+1wa5sQGav/" "2FsLHUVn6cGSi0LlFwLewGHPFJDLR0u4t7ZUyM//" "x6da0sWgOa5hzDqjsVGmjxEHXiaXKW3i4iSZNuxoNbMQkIbVML+" "DkYu9ND0O2swg4itGeVSzXA==", - uint64_t{0x4d612125bdc4fd00}, uint64_t{0xecf3de1acd04651f}}, + uint64_t{0x4d612125bdc4fd00}}, {"Ntf1bMRdondtMv1CYr3G80iDJ4WSAlKy5H34XdGruQiCrnRGDBa+" "eUi7vKp4gp3BBcVGl8eYSasVQQjn7MLvb3BjtXx6c/" "bCL7JtpzQKaDnPr9GWRxpBXVxKREgMM7d8lm35EODv0w+" "hQLfVSh8OGs7fsBb68nNWPLeeSOo=", - uint64_t{0x81826b553954464e}, uint64_t{0xcc0a40552559ff32}}, + uint64_t{0x81826b553954464e}}, {"VsSAw72Ro6xks02kaiLuiTEIWBC5bgqr4WDnmP8vglXzAhixk7td926rm9jNimL+" "kroPSygZ9gl63aF5DCPOACXmsbmhDrAQuUzoh9ZKhWgElLQsrqo1KIjWoZT5b5QfVUXY9lS" "IBg3U75SqORoTPq7HalxxoIT5diWOcJQi", - uint64_t{0xc2e5d345dc0ddd2d}, uint64_t{0xc385c374f20315b1}}, + uint64_t{0xc2e5d345dc0ddd2d}}, {"j+loZ+C87+" "bJxNVebg94gU0mSLeDulcHs84tQT7BZM2rzDSLiCNxUedHr1ZWJ9ejTiBa0dqy2I2ABc++" "xzOLcv+//YfibtjKtYggC6/3rv0XCc7xu6d/" "O6xO+XOBhOWAQ+IHJVHf7wZnDxIXB8AUHsnjEISKj7823biqXjyP3g==", - uint64_t{0x3da6830a9e32631e}, uint64_t{0xb90208a4c7234183}}, + uint64_t{0x3da6830a9e32631e}}, {"f3LlpcPElMkspNtDq5xXyWU62erEaKn7RWKlo540gR6mZsNpK1czV/" "sOmqaq8XAQLEn68LKj6/" "cFkJukxRzCa4OF1a7cCAXYFp9+wZDu0bw4y63qbpjhdCl8GO6Z2lkcXy7KOzbPE01ukg7+" "gN+7uKpoohgAhIwpAKQXmX5xtd0=", - uint64_t{0xc9ae5c8759b4877a}, uint64_t{0x58aa1ca7a4c075d9}}, + uint64_t{0xc9ae5c8759b4877a}}, + }; + +#if defined(__aarch64__) + constexpr uint64_t kGolden[kNumGoldenOutputs] = { + 0x45c0aadee165dcbe, 0x25ed8587f6f20d06, 0x5f23ae668ce7926d, + 0xfef74d1da0846719, 0x54478408e68cb7d4, 0xee27ddaf88c6fe68, + 0xb7ac7031e81867ca, 0xf1168f818ec6c36d, 0x1dd0b734a83b019a, + 0xd6ae30d4142b54fe, 0xcd860c721ccb80fb, 0x068acf8493794756, + 0xd4ada0be58681307, 0x13ffe0f64ca540ed, 0xffc1d7a3401aec02, + 0xd81c4d865cf95fb9, 0x1dd0793acede62e0, 0xa6722abbca8fe4cf, + 0x5453d3e4111a7e40, 0xf29b3e3204c9dcd2, 0x23be2980e43117f7, + 0x74e2ccbc286f08eb, 0x19ef7c0f9496003a, 0xbfbf1c3e49b27987, + 0x6e6c179eb4a82c70, 0x07f4e184216bc4fc, 0xf17fbc4254927554, + 0xe57696b70a45b1b6, 0x6d3b144631b320e8, 0xccf8729792c75a2d, + 0xe832495b41fa980b, 0x5c96cfdc7b227d34, 0xc4dca234ef4e43f4, + 0x5fc801abf9abe307, 0xe41e3c5076d88f4d, 0x522346200ddec3c3, + 0x72bed1946fd7aaa4, 0x0ac1f84dcc335f96, 0x3af78db5e0a47670, + 0x6100ebf1481f1caf, 0xf5fd10037fc651a3, 0xa01227d8944665f3, + 0x7217681c4bbc9420, 0x4adee538e3eb10d1, 0x35e1761ad96de9a7, + 0x8b370aef9613bfba, 0x824506f749eeaf59, 0x85e805fa04423991, + 0xb61e9c33283c3de7, 0xc79721bbcb039ed6, 0x04e1c19a3a1e6639, + 0x6aaf6346b68dd638, 0x601a4b496be6d0c4, 0x3ece355f91c41787, + 0xd2fc8998448d7888, 0xd7529804f843efa9, 0xabdcc38a288536aa, + 0xdd323e48a9718648, 0x2090279c0030a52a, 0xe2f90faca88a3cd1, + 0x3e0c4e92fc50e4aa, 0xa26d308798e801dd, 0x432eefeedee8c02e, + 0xca4ce494614b77df, 0xbba82911e838066d, 0x4b00821016adee4b, + 0x4cf6e526dfb5a20f, 0x5b8466495142cba2, 0xe28ac1406e88a68c, + 0x8511e5f9d3100999, 0x05acbfe02798890b, 0x74c249c7ce4a8425, + 0xdbe7468d09bc34bc, 0x11079ab10e3b9b58, 0xb7788dec9032035a, + 0xb7e8daa786513f80, 0x34c3288831f46b45, 0x014cce5f0c21ecc6, + 0xc6a8f7b024551a28, 0x49784e902e207fd8, 0x4720d32af0b55158, + 0x8df3ec5de0c1da00, 0xf4db677b2c9e6853, 0xaa419abea78d312d, + 0x181e0f91bd757443, 0xa8c45136fada083b, 0x91303b93f5f0582c, + 0x883b95c6ddc62a08, 0x93186a8875fe952b, 0xd94f533928e957e2, + 0x6ba343003e10c172, 0xc8623b620c715d6a, 0x8ca0c512e180e244, + 0xdc9b74c2536b6216, 0x8eb5fdc61b295d96, 0x2ad83966b37c95ba, + 0xb90bf154ac5edec9, 0x902cf847b326cfb3, 0x7b02d0c0ca7808ca, + 0x492f310d003ea15f, 0x3eb6497a47c95990, 0x5d46b0ced31428b7, + 0x081afa67d1986157, 0x043482ec286b20eb, 0xc103c8f18c1a2a53, + 0xe8e9995a81481e83, 0x6bb3295822bc90b5, 0xeec75297a3fa5672, + 0x591c8440c4857412, 0x74947f455aaf24ad, 0xcf0e571586ec77a9, + 0x0c2553ea8c0400ad, 0x380219118066255f, 0x7595adb88b15ebe2, + 0xb33c00696c64ae23, 0xa143516ddd7c9857, 0x39179af229248d26, + 0x65d387a6f2ee2079, 0x89f8a9b21cd2f195, 0xbfef032d25df92e6, + 0x6b7e18a36c69da71, 0x4b3b15f6c28974e6, 0x032a75917f6c544c, + 0xe3b97ecca6d287cd, 0xa4a563110d3cda81, 0x35e09e8134f4e7f1, + 0xc9419dd03a9a390e, 0x7b86fae9000fd329, 0x1e044f8d54fe74c3, + 0x9c4991d7a47e9666, 0xfb485f3a1df4fdb6, 0xb11519969eeb94ff, + 0x3224ea1c44caeb8d, 0x86570bbd7cc6b80d, }; +#else + constexpr uint64_t kGolden[kNumGoldenOutputs] = { + 0xe5a40d39ab796423, 0x1766974bf7527d81, 0x5c3bbbe230db17a8, + 0xa6630143a7e6aa6f, 0x8787cb2d04b0c984, 0x33603654ff574ac2, + 0xa6564b468248c683, 0xef192f401b116e1c, 0xbe8dc0c54617639d, + 0x93d7f665b5521c8e, 0x646d70bb42445f28, 0x96a7b1e3cc9bd426, + 0x76020289ab0790c4, 0x39f842e4133b9b44, 0x2b8d7047be4bcaab, + 0x99628abef6716a97, 0x4432e02ba42b2740, 0x74d810efcad7918a, + 0x88c84e986002507f, 0x4f99acf193cf39b9, 0xd90e7a3655891e37, + 0x3bb378b1d4df8fcf, 0xf78e94045c052d47, 0x26da0b2130da6b40, + 0x30b4d426af8c6986, 0x5413b4aaf3baaeae, 0x756ab265370a1597, + 0xdaf5f4b7d09814fb, 0x8f874ae37742b75e, 0x8fecd03956121ce8, + 0x229c292ea7a08285, 0x0bb4bf0692d14bae, 0x207b24ca3bdac1db, + 0x64f6cd6745d3825b, 0xa2b2e1656b58df1e, 0x0d01d30d9ee7a148, + 0x1cb4cd00ab804e3b, 0x4697f2637fd90999, 0x8383a756b5688c07, + 0x695c29cb3696a975, 0xda2e5a5a5e971521, 0x7935d4befa056b2b, + 0x38dd541ca95420fe, 0xcc06c7a4963f967f, 0xbf0f6f66e232fb20, + 0xf7efb32d373fe71a, 0xe2e64634b1c12660, 0x285b8fd1638e306d, + 0x658e8a4e3b714d6c, 0xf391fb968e0eb398, 0x744a9ea0cc144bf2, + 0x12636f2be11012f1, 0x29c57de825948f80, 0x58c6f99ab0d1c021, + 0x13e7b5a7b82fe3bb, 0x10fbc87901e02b63, 0xa24c9184901b748b, + 0xcac4fd4c5080e581, 0xc38bdb7483ba68e1, 0xdb2a8069b2ceaffa, + 0xdf9fe91d0d1c7887, 0xe83f49e96e2e6a08, 0x0c69e61b62ca2b62, + 0xb4a4f3f85f8298fe, 0x167a1b39e1e95f41, 0xf8a2a5649855ee41, + 0x27992565b595c498, 0x3e08cca5b71f9346, 0xad406b10c770a6d2, + 0xd1713ce6e552bcf2, 0x753b287194c73ad3, 0x5ae41a95f600af1c, + 0x4a61163b86a8bb4c, 0x42eeaa79e760c7e4, 0x698df622ef465b0a, + 0x157583111e1a6026, 0xaa1388f078e793e0, 0xf10d68d0f3309360, + 0x2af056184457a3de, 0x6d0058e1590b2489, 0x638f287f68817f12, + 0xc46b71fecefd5467, 0x2c8e94679d964e0a, 0x8612b797ce22503a, + 0x59f929babfba7170, 0x9527556923fb49a0, 0x1039ab644f5e150b, + 0x7816c83f3aa05e6d, 0xf51d2f564518c619, 0x67d494cff03ac004, + 0x2802d636ced1cfbb, 0xf64e20bad771cb12, 0x0b9a6cf84a83e15e, + 0x8da6630319609301, 0x40946a86e2a996f3, 0xcab7f5997953fa76, + 0x39129ca0e04fc465, 0x5238221fd685e1b8, 0x175130c407dbcaab, + 0x02f20e7536c0b0df, 0x2742cb488a04ad56, 0xd6afb593879ff93b, + 0xf50ad64caac0ca7f, 0x2ade95c4261364ae, 0x5c4f3299faacd07a, + 0xfffe3bff0ae5e9bc, 0x1db785c0005166e4, 0xea000d962ad18418, + 0xe42aef38359362d9, 0xc8e95657348a3891, 0xc162eca864f238c6, + 0xbe1fb373e20579ad, 0x628a1d4f40aa6ffd, 0xa87bdb7456340f90, + 0x5960ef3ba982c801, 0x5026586df9a431ec, 0xfe4b8a20fdf0840b, + 0xdcb761867da7072f, 0xc10d4653667275b7, 0x727720deec13110b, + 0x710b009662858dc9, 0xfbf8f7a3ecac1eb7, 0xb6fc4fcd0722e3df, + 0x7cb86dcc55104aac, 0x19e71e9b45c3a51e, 0x51de38573c2bea48, + 0xa73ab6996d6df158, 0x55ef2b8c930817b2, 0xb2850bf5fae87157, + 0xecf3de1acd04651f, 0xcc0a40552559ff32, 0xc385c374f20315b1, + 0xb90208a4c7234183, 0x58aa1ca7a4c075d9, + }; +#endif - for (const auto& expected_result : expected_results) { +#if UPDATE_GOLDEN + (void)kGolden; // Silence warning. + for (size_t i = 0; i < kNumGoldenOutputs; ++i) { + std::string str; + ASSERT_TRUE(absl::Base64Unescape(cases[i].base64_data, &str)); + uint64_t h = absl::hash_internal::LowLevelHash(str.data(), str.size(), + cases[i].seed, kSalt); + printf("0x%016" PRIx64 ", ", h); + if (i % 3 == 2) { + printf("\n"); + } + } + printf("\n\n\n"); + EXPECT_FALSE(true); +#else + for (size_t i = 0; i < kNumGoldenOutputs; ++i) { + SCOPED_TRACE(::testing::Message() + << "i = " << i << "; input = " << cases[i].base64_data); std::string str; - ASSERT_TRUE(absl::Base64Unescape(expected_result.base64_data, &str)); + ASSERT_TRUE(absl::Base64Unescape(cases[i].base64_data, &str)); EXPECT_EQ(absl::hash_internal::LowLevelHash(str.data(), str.size(), - expected_result.seed, kSalt), - expected_result.hash); + cases[i].seed, kSalt), + kGolden[i]); } +#endif } } // namespace diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index a9cbe489..c7ad96be 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h @@ -586,10 +586,10 @@ inline uint128& uint128::operator=(int128 v) { // Arithmetic operators. -uint128 operator<<(uint128 lhs, int amount); -uint128 operator>>(uint128 lhs, int amount); -uint128 operator+(uint128 lhs, uint128 rhs); -uint128 operator-(uint128 lhs, uint128 rhs); +constexpr uint128 operator<<(uint128 lhs, int amount); +constexpr uint128 operator>>(uint128 lhs, int amount); +constexpr uint128 operator+(uint128 lhs, uint128 rhs); +constexpr uint128 operator-(uint128 lhs, uint128 rhs); uint128 operator*(uint128 lhs, uint128 rhs); uint128 operator/(uint128 lhs, uint128 rhs); uint128 operator%(uint128 lhs, uint128 rhs); @@ -786,7 +786,7 @@ inline uint128::operator long double() const { // Comparison operators. -inline bool operator==(uint128 lhs, uint128 rhs) { +constexpr bool operator==(uint128 lhs, uint128 rhs) { #if defined(ABSL_HAVE_INTRINSIC_INT128) return static_cast(lhs) == static_cast(rhs); @@ -796,11 +796,9 @@ inline bool operator==(uint128 lhs, uint128 rhs) { #endif } -inline bool operator!=(uint128 lhs, uint128 rhs) { - return !(lhs == rhs); -} +constexpr bool operator!=(uint128 lhs, uint128 rhs) { return !(lhs == rhs); } -inline bool operator<(uint128 lhs, uint128 rhs) { +constexpr bool operator<(uint128 lhs, uint128 rhs) { #ifdef ABSL_HAVE_INTRINSIC_INT128 return static_cast(lhs) < static_cast(rhs); @@ -811,11 +809,11 @@ inline bool operator<(uint128 lhs, uint128 rhs) { #endif } -inline bool operator>(uint128 lhs, uint128 rhs) { return rhs < lhs; } +constexpr bool operator>(uint128 lhs, uint128 rhs) { return rhs < lhs; } -inline bool operator<=(uint128 lhs, uint128 rhs) { return !(rhs < lhs); } +constexpr bool operator<=(uint128 lhs, uint128 rhs) { return !(rhs < lhs); } -inline bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); } +constexpr bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); } // Unary operators. @@ -827,14 +825,13 @@ constexpr inline int128 operator+(int128 val) { return val; } -inline uint128 operator-(uint128 val) { +constexpr uint128 operator-(uint128 val) { #if defined(ABSL_HAVE_INTRINSIC_INT128) return -static_cast(val); #else - uint64_t hi = ~Uint128High64(val); - uint64_t lo = ~Uint128Low64(val) + 1; - if (lo == 0) ++hi; // carry - return MakeUint128(hi, lo); + return MakeUint128( + ~Uint128High64(val) + static_cast(Uint128Low64(val) == 0), + ~Uint128Low64(val) + 1); #endif } @@ -903,67 +900,77 @@ inline uint128& uint128::operator^=(uint128 other) { // Arithmetic operators. -inline uint128 operator<<(uint128 lhs, int amount) { +constexpr uint128 operator<<(uint128 lhs, int amount) { #ifdef ABSL_HAVE_INTRINSIC_INT128 return static_cast(lhs) << amount; #else // uint64_t shifts of >= 64 are undefined, so we will need some // special-casing. - if (amount < 64) { - if (amount != 0) { - return MakeUint128( - (Uint128High64(lhs) << amount) | (Uint128Low64(lhs) >> (64 - amount)), - Uint128Low64(lhs) << amount); - } - return lhs; - } - return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0); + return amount >= 64 ? MakeUint128(Uint128Low64(lhs) << (amount - 64), 0) + : amount == 0 ? lhs + : MakeUint128((Uint128High64(lhs) << amount) | + (Uint128Low64(lhs) >> (64 - amount)), + Uint128Low64(lhs) << amount); #endif } -inline uint128 operator>>(uint128 lhs, int amount) { +constexpr uint128 operator>>(uint128 lhs, int amount) { #ifdef ABSL_HAVE_INTRINSIC_INT128 return static_cast(lhs) >> amount; #else // uint64_t shifts of >= 64 are undefined, so we will need some // special-casing. - if (amount < 64) { - if (amount != 0) { - return MakeUint128(Uint128High64(lhs) >> amount, - (Uint128Low64(lhs) >> amount) | - (Uint128High64(lhs) << (64 - amount))); - } - return lhs; - } - return MakeUint128(0, Uint128High64(lhs) >> (amount - 64)); + return amount >= 64 ? MakeUint128(0, Uint128High64(lhs) >> (amount - 64)) + : amount == 0 ? lhs + : MakeUint128(Uint128High64(lhs) >> amount, + (Uint128Low64(lhs) >> amount) | + (Uint128High64(lhs) << (64 - amount))); #endif } -inline uint128 operator+(uint128 lhs, uint128 rhs) { +#if !defined(ABSL_HAVE_INTRINSIC_INT128) +namespace int128_internal { +constexpr uint128 AddResult(uint128 result, uint128 lhs) { + // check for carry + return (Uint128Low64(result) < Uint128Low64(lhs)) + ? MakeUint128(Uint128High64(result) + 1, Uint128Low64(result)) + : result; +} +} // namespace int128_internal +#endif + +constexpr uint128 operator+(uint128 lhs, uint128 rhs) { #if defined(ABSL_HAVE_INTRINSIC_INT128) return static_cast(lhs) + static_cast(rhs); #else - uint128 result = MakeUint128(Uint128High64(lhs) + Uint128High64(rhs), - Uint128Low64(lhs) + Uint128Low64(rhs)); - if (Uint128Low64(result) < Uint128Low64(lhs)) { // check for carry - return MakeUint128(Uint128High64(result) + 1, Uint128Low64(result)); - } - return result; + return int128_internal::AddResult( + MakeUint128(Uint128High64(lhs) + Uint128High64(rhs), + Uint128Low64(lhs) + Uint128Low64(rhs)), + lhs); #endif } -inline uint128 operator-(uint128 lhs, uint128 rhs) { +#if !defined(ABSL_HAVE_INTRINSIC_INT128) +namespace int128_internal { +constexpr uint128 SubstructResult(uint128 result, uint128 lhs, uint128 rhs) { + // check for carry + return (Uint128Low64(lhs) < Uint128Low64(rhs)) + ? MakeUint128(Uint128High64(result) - 1, Uint128Low64(result)) + : result; +} +} // namespace int128_internal +#endif + +constexpr uint128 operator-(uint128 lhs, uint128 rhs) { #if defined(ABSL_HAVE_INTRINSIC_INT128) return static_cast(lhs) - static_cast(rhs); #else - uint128 result = MakeUint128(Uint128High64(lhs) - Uint128High64(rhs), - Uint128Low64(lhs) - Uint128Low64(rhs)); - if (Uint128Low64(lhs) < Uint128Low64(rhs)) { // check for carry - return MakeUint128(Uint128High64(result) - 1, Uint128Low64(result)); - } - return result; + return int128_internal::SubstructResult( + MakeUint128(Uint128High64(lhs) - Uint128High64(rhs), + Uint128Low64(lhs) - Uint128Low64(rhs)), + lhs, rhs); #endif } @@ -1063,17 +1070,17 @@ inline int128& int128::operator=(unsigned long long v) { } // Arithmetic operators. - -int128 operator+(int128 lhs, int128 rhs); -int128 operator-(int128 lhs, int128 rhs); +constexpr int128 operator-(int128 v); +constexpr int128 operator+(int128 lhs, int128 rhs); +constexpr int128 operator-(int128 lhs, int128 rhs); int128 operator*(int128 lhs, int128 rhs); int128 operator/(int128 lhs, int128 rhs); int128 operator%(int128 lhs, int128 rhs); -int128 operator|(int128 lhs, int128 rhs); -int128 operator&(int128 lhs, int128 rhs); -int128 operator^(int128 lhs, int128 rhs); -int128 operator<<(int128 lhs, int amount); -int128 operator>>(int128 lhs, int amount); +constexpr int128 operator|(int128 lhs, int128 rhs); +constexpr int128 operator&(int128 lhs, int128 rhs); +constexpr int128 operator^(int128 lhs, int128 rhs); +constexpr int128 operator<<(int128 lhs, int amount); +constexpr int128 operator>>(int128 lhs, int amount); inline int128& int128::operator+=(int128 other) { *this = *this + other; @@ -1125,6 +1132,9 @@ inline int128& int128::operator>>=(int amount) { return *this; } +// Forward declaration for comparison operators. +constexpr bool operator!=(int128 lhs, int128 rhs); + namespace int128_internal { // Casts from unsigned to signed while preserving the underlying binary diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc index d6c76dd3..3945fa29 100644 --- a/absl/numeric/int128_have_intrinsic.inc +++ b/absl/numeric/int128_have_intrinsic.inc @@ -155,7 +155,7 @@ constexpr int128::operator unsigned __int128() const { #if defined(__clang__) && !defined(__ppc64__) inline int128::operator float() const { return static_cast(v_); } -inline int128::operator double () const { return static_cast(v_); } +inline int128::operator double() const { return static_cast(v_); } inline int128::operator long double() const { return static_cast(v_); @@ -163,8 +163,8 @@ inline int128::operator long double() const { #else // Clang on PowerPC // Forward declaration for conversion operators to floating point types. -int128 operator-(int128 v); -bool operator!=(int128 lhs, int128 rhs); +constexpr int128 operator-(int128 v); +constexpr bool operator!=(int128 lhs, int128 rhs); inline int128::operator float() const { // We must convert the absolute value and then negate as needed, because @@ -199,51 +199,45 @@ inline int128::operator long double() const { // Comparison operators. -inline bool operator==(int128 lhs, int128 rhs) { +constexpr bool operator==(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) == static_cast<__int128>(rhs); } -inline bool operator!=(int128 lhs, int128 rhs) { +constexpr bool operator!=(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) != static_cast<__int128>(rhs); } -inline bool operator<(int128 lhs, int128 rhs) { +constexpr bool operator<(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) < static_cast<__int128>(rhs); } -inline bool operator>(int128 lhs, int128 rhs) { +constexpr bool operator>(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) > static_cast<__int128>(rhs); } -inline bool operator<=(int128 lhs, int128 rhs) { +constexpr bool operator<=(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) <= static_cast<__int128>(rhs); } -inline bool operator>=(int128 lhs, int128 rhs) { +constexpr bool operator>=(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) >= static_cast<__int128>(rhs); } // Unary operators. -inline int128 operator-(int128 v) { - return -static_cast<__int128>(v); -} +constexpr int128 operator-(int128 v) { return -static_cast<__int128>(v); } -inline bool operator!(int128 v) { - return !static_cast<__int128>(v); -} +constexpr bool operator!(int128 v) { return !static_cast<__int128>(v); } -inline int128 operator~(int128 val) { - return ~static_cast<__int128>(val); -} +constexpr int128 operator~(int128 val) { return ~static_cast<__int128>(val); } // Arithmetic operators. -inline int128 operator+(int128 lhs, int128 rhs) { +constexpr int128 operator+(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) + static_cast<__int128>(rhs); } -inline int128 operator-(int128 lhs, int128 rhs) { +constexpr int128 operator-(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) - static_cast<__int128>(rhs); } @@ -281,22 +275,22 @@ inline int128& int128::operator--() { return *this; } -inline int128 operator|(int128 lhs, int128 rhs) { +constexpr int128 operator|(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) | static_cast<__int128>(rhs); } -inline int128 operator&(int128 lhs, int128 rhs) { +constexpr int128 operator&(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) & static_cast<__int128>(rhs); } -inline int128 operator^(int128 lhs, int128 rhs) { +constexpr int128 operator^(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) ^ static_cast<__int128>(rhs); } -inline int128 operator<<(int128 lhs, int amount) { +constexpr int128 operator<<(int128 lhs, int amount) { return static_cast<__int128>(lhs) << amount; } -inline int128 operator>>(int128 lhs, int amount) { +constexpr int128 operator>>(int128 lhs, int amount) { return static_cast<__int128>(lhs) >> amount; } diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc index c753771a..66f6809f 100644 --- a/absl/numeric/int128_no_intrinsic.inc +++ b/absl/numeric/int128_no_intrinsic.inc @@ -134,10 +134,6 @@ constexpr int128::operator unsigned long long() const { // NOLINT(runtime/int) return static_cast(lo_); // NOLINT(runtime/int) } -// Forward declaration for conversion operators to floating point types. -int128 operator-(int128 v); -bool operator!=(int128 lhs, int128 rhs); - inline int128::operator float() const { // We must convert the absolute value and then negate as needed, because // floating point types are typically sign-magnitude. Otherwise, the @@ -169,76 +165,80 @@ inline int128::operator long double() const { // Comparison operators. -inline bool operator==(int128 lhs, int128 rhs) { +constexpr bool operator==(int128 lhs, int128 rhs) { return (Int128Low64(lhs) == Int128Low64(rhs) && Int128High64(lhs) == Int128High64(rhs)); } -inline bool operator!=(int128 lhs, int128 rhs) { - return !(lhs == rhs); -} +constexpr bool operator!=(int128 lhs, int128 rhs) { return !(lhs == rhs); } -inline bool operator<(int128 lhs, int128 rhs) { +constexpr bool operator<(int128 lhs, int128 rhs) { return (Int128High64(lhs) == Int128High64(rhs)) ? (Int128Low64(lhs) < Int128Low64(rhs)) : (Int128High64(lhs) < Int128High64(rhs)); } -inline bool operator>(int128 lhs, int128 rhs) { +constexpr bool operator>(int128 lhs, int128 rhs) { return (Int128High64(lhs) == Int128High64(rhs)) ? (Int128Low64(lhs) > Int128Low64(rhs)) : (Int128High64(lhs) > Int128High64(rhs)); } -inline bool operator<=(int128 lhs, int128 rhs) { - return !(lhs > rhs); -} +constexpr bool operator<=(int128 lhs, int128 rhs) { return !(lhs > rhs); } -inline bool operator>=(int128 lhs, int128 rhs) { - return !(lhs < rhs); -} +constexpr bool operator>=(int128 lhs, int128 rhs) { return !(lhs < rhs); } // Unary operators. -inline int128 operator-(int128 v) { - int64_t hi = ~Int128High64(v); - uint64_t lo = ~Int128Low64(v) + 1; - if (lo == 0) ++hi; // carry - return MakeInt128(hi, lo); +constexpr int128 operator-(int128 v) { + return MakeInt128(~Int128High64(v) + (Int128Low64(v) == 0), + ~Int128Low64(v) + 1); } -inline bool operator!(int128 v) { +constexpr bool operator!(int128 v) { return !Int128Low64(v) && !Int128High64(v); } -inline int128 operator~(int128 val) { +constexpr int128 operator~(int128 val) { return MakeInt128(~Int128High64(val), ~Int128Low64(val)); } // Arithmetic operators. -inline int128 operator+(int128 lhs, int128 rhs) { - int128 result = MakeInt128(Int128High64(lhs) + Int128High64(rhs), - Int128Low64(lhs) + Int128Low64(rhs)); - if (Int128Low64(result) < Int128Low64(lhs)) { // check for carry - return MakeInt128(Int128High64(result) + 1, Int128Low64(result)); - } - return result; +namespace int128_internal { +constexpr int128 SignedAddResult(int128 result, int128 lhs) { + // check for carry + return (Int128Low64(result) < Int128Low64(lhs)) + ? MakeInt128(Int128High64(result) + 1, Int128Low64(result)) + : result; +} +} // namespace int128_internal +constexpr int128 operator+(int128 lhs, int128 rhs) { + return int128_internal::SignedAddResult( + MakeInt128(Int128High64(lhs) + Int128High64(rhs), + Int128Low64(lhs) + Int128Low64(rhs)), + lhs); } -inline int128 operator-(int128 lhs, int128 rhs) { - int128 result = MakeInt128(Int128High64(lhs) - Int128High64(rhs), - Int128Low64(lhs) - Int128Low64(rhs)); - if (Int128Low64(lhs) < Int128Low64(rhs)) { // check for carry - return MakeInt128(Int128High64(result) - 1, Int128Low64(result)); - } - return result; +namespace int128_internal { +constexpr int128 SignedSubstructResult(int128 result, int128 lhs, int128 rhs) { + // check for carry + return (Int128Low64(lhs) < Int128Low64(rhs)) + ? MakeInt128(Int128High64(result) - 1, Int128Low64(result)) + : result; +} +} // namespace int128_internal +constexpr int128 operator-(int128 lhs, int128 rhs) { + return int128_internal::SignedSubstructResult( + MakeInt128(Int128High64(lhs) - Int128High64(rhs), + Int128Low64(lhs) - Int128Low64(rhs)), + lhs, rhs); } inline int128 operator*(int128 lhs, int128 rhs) { - uint128 result = uint128(lhs) * rhs; - return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(result)), - Uint128Low64(result)); + return MakeInt128( + int128_internal::BitCastToSigned(Uint128High64(uint128(lhs) * rhs)), + Uint128Low64(uint128(lhs) * rhs)); } inline int128 int128::operator++(int) { @@ -263,46 +263,43 @@ inline int128& int128::operator--() { return *this; } -inline int128 operator|(int128 lhs, int128 rhs) { +constexpr int128 operator|(int128 lhs, int128 rhs) { return MakeInt128(Int128High64(lhs) | Int128High64(rhs), Int128Low64(lhs) | Int128Low64(rhs)); } -inline int128 operator&(int128 lhs, int128 rhs) { +constexpr int128 operator&(int128 lhs, int128 rhs) { return MakeInt128(Int128High64(lhs) & Int128High64(rhs), Int128Low64(lhs) & Int128Low64(rhs)); } -inline int128 operator^(int128 lhs, int128 rhs) { +constexpr int128 operator^(int128 lhs, int128 rhs) { return MakeInt128(Int128High64(lhs) ^ Int128High64(rhs), Int128Low64(lhs) ^ Int128Low64(rhs)); } -inline int128 operator<<(int128 lhs, int amount) { +constexpr int128 operator<<(int128 lhs, int amount) { // uint64_t shifts of >= 64 are undefined, so we need some special-casing. - if (amount < 64) { - if (amount != 0) { - return MakeInt128( - (Int128High64(lhs) << amount) | - static_cast(Int128Low64(lhs) >> (64 - amount)), - Int128Low64(lhs) << amount); - } - return lhs; - } - return MakeInt128(static_cast(Int128Low64(lhs) << (amount - 64)), 0); -} - -inline int128 operator>>(int128 lhs, int amount) { + return amount >= 64 + ? MakeInt128( + static_cast(Int128Low64(lhs) << (amount - 64)), 0) + : amount == 0 + ? lhs + : MakeInt128( + (Int128High64(lhs) << amount) | + static_cast(Int128Low64(lhs) >> (64 - amount)), + Int128Low64(lhs) << amount); +} + +constexpr int128 operator>>(int128 lhs, int amount) { // uint64_t shifts of >= 64 are undefined, so we need some special-casing. - if (amount < 64) { - if (amount != 0) { - return MakeInt128( - Int128High64(lhs) >> amount, - (Int128Low64(lhs) >> amount) | - (static_cast(Int128High64(lhs)) << (64 - amount))); - } - return lhs; - } - return MakeInt128(0, - static_cast(Int128High64(lhs) >> (amount - 64))); + return amount >= 64 + ? MakeInt128( + 0, static_cast(Int128High64(lhs) >> (amount - 64))) + : amount == 0 + ? lhs + : MakeInt128(Int128High64(lhs) >> amount, + (Int128Low64(lhs) >> amount) | + (static_cast(Int128High64(lhs)) + << (64 - amount))); } -- cgit v1.2.3 From 29f8307d8e629e989bf26a84ab1a49a0738a5470 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 20 Sep 2021 13:35:36 -0700 Subject: Export of internal Abseil changes -- d56207f5535c3aad1624e33d20777ea6e66f51a7 by Abseil Team : Internal change PiperOrigin-RevId: 397830482 -- 7f7ff3e88e0d3cd61d63da477b2a08e61a1aeea2 by Evan Brown : Update implementation details comment in raw_hash_set to include information about the heap allocation's layout. PiperOrigin-RevId: 397786239 -- fde783b12a79ae8d587d1027bc8736dff6844897 by Abseil Team : Add comments on #endif to make nesting clearer PiperOrigin-RevId: 397684219 GitOrigin-RevId: d56207f5535c3aad1624e33d20777ea6e66f51a7 Change-Id: I43dc2b5c982f1ef2b21f82b6133c49c428baf223 --- absl/container/internal/raw_hash_set.h | 11 +++++++++++ absl/debugging/internal/stacktrace_config.h | 11 ++++++----- absl/profiling/BUILD.bazel | 4 +++- 3 files changed, 20 insertions(+), 6 deletions(-) (limited to 'absl/debugging') diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 212052ea..5c5db12e 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -87,6 +87,17 @@ // // This probing function guarantees that after N probes, all the groups of the // table will be probed exactly once. +// +// The control state and slot array are stored contiguously in a shared heap +// allocation. The layout of this allocation is: `capacity()` control bytes, +// one sentinel control byte, `Group::kWidth - 1` cloned control bytes, +// , `capacity()` slots. The sentinel control byte is used in +// iteration so we know when we reach the end of the table. The cloned control +// bytes at the end of the table are cloned from the beginning of the table so +// groups that begin near the end of the table can see a full group. In cases in +// which there are more than `capacity()` cloned control bytes, the extra bytes +// are `kEmpty`, and these ensure that we always see at least one empty slot and +// can stop an unsuccessful search. #ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ #define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h index 29b26bdd..ff21b719 100644 --- a/absl/debugging/internal/stacktrace_config.h +++ b/absl/debugging/internal/stacktrace_config.h @@ -35,7 +35,7 @@ // Thread local support required for UnwindImpl. #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_generic-inl.inc" -#endif +#endif // defined(ABSL_HAVE_THREAD_LOCAL) #elif defined(__EMSCRIPTEN__) #define ABSL_STACKTRACE_INL_HEADER \ @@ -55,7 +55,7 @@ // Note: When using glibc this may require -funwind-tables to function properly. #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_generic-inl.inc" -#endif +#endif // __has_include() #elif defined(__i386__) || defined(__x86_64__) #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_x86-inl.inc" @@ -73,9 +73,10 @@ // Note: When using glibc this may require -funwind-tables to function properly. #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_generic-inl.inc" -#endif -#endif -#endif +#endif // __has_include() +#endif // defined(__has_include) + +#endif // defined(__linux__) && !defined(__ANDROID__) // Fallback to the empty implementation. #if !defined(ABSL_STACKTRACE_INL_HEADER) diff --git a/absl/profiling/BUILD.bazel b/absl/profiling/BUILD.bazel index 5f3a1030..ba4811b3 100644 --- a/absl/profiling/BUILD.bazel +++ b/absl/profiling/BUILD.bazel @@ -27,7 +27,9 @@ cc_library( hdrs = ["internal/sample_recorder.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = ["//absl:__subpackages__"], + visibility = [ + "//absl:__subpackages__", + ], deps = [ "//absl/base:config", "//absl/base:core_headers", -- cgit v1.2.3 From 1ce4ceca2b2931bc4d7e470228c2dbb2f3dfea0f Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 23 Sep 2021 13:21:54 -0700 Subject: Export of internal Abseil changes -- 1801102e11205861bc063e067e9fd4754b625c5a by Derek Mauro : Internal change PiperOrigin-RevId: 398562681 -- 485008445725d4013f60f4b2876f84b6b47932ec by Jorg Brown : Replace calls to std::isinf with comparison against max(). PiperOrigin-RevId: 398534255 -- 9b99d074d39ad677cf92f99549d22bb73f504f8f by Saleem Abdulrasool : debugging: add support for non-glibc targets for debugging This relaxes the ELF mem_image handling and subsequently enables the VDSO support for non-glibc targets. The primary need for the restriction was the use of the `__GLIBC_PREREQ` macro. If it is undefined, assume that the glibc pre-requisite is unavailable. This allows building the debugging_internal target on musl targets. PiperOrigin-RevId: 398499050 -- 3cc3630ef2226ae1981a944573f0f9c27a527ebf by Abseil Team : Replace usages of `auto` with proper typedefs. PiperOrigin-RevId: 398479551 GitOrigin-RevId: 1801102e11205861bc063e067e9fd4754b625c5a Change-Id: Ib13e8612d1b263b9c1ae7f56a9f394b24c3add2e --- absl/container/internal/inlined_vector.h | 10 +++++----- absl/debugging/internal/elf_mem_image.cc | 21 +++++++++++---------- absl/debugging/internal/elf_mem_image.h | 4 ++-- absl/debugging/internal/vdso_support.cc | 19 ++++++++++++++++--- absl/strings/numbers.cc | 2 +- 5 files changed, 35 insertions(+), 21 deletions(-) (limited to 'absl/debugging') diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index bb365b80..e2ecf46c 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h @@ -98,7 +98,7 @@ template void DestroyElements(NoTypeDeduction& allocator, Pointer destroy_first, SizeType destroy_size) { if (destroy_first != nullptr) { - for (auto i = destroy_size; i != 0;) { + for (SizeType i = destroy_size; i != 0;) { --i; AllocatorTraits::destroy(allocator, destroy_first + i); } @@ -492,7 +492,7 @@ void Storage::DestroyContents() { template void Storage::InitFrom(const Storage& other) { - const auto n = other.GetSize(); + const SizeType n = other.GetSize(); assert(n > 0); // Empty sources handled handled in caller. ConstPointer src; Pointer dst; @@ -598,9 +598,9 @@ template auto Storage::Resize(ValueAdapter values, SizeType new_size) -> void { StorageView storage_view = MakeStorageView(); - auto* const base = storage_view.data; + Pointer const base = storage_view.data; const SizeType size = storage_view.size; - auto& alloc = GetAllocator(); + A& alloc = GetAllocator(); if (new_size <= size) { // Destroy extra old elements. DestroyElements(alloc, base + new_size, size - new_size); @@ -732,7 +732,7 @@ template template auto Storage::EmplaceBack(Args&&... args) -> Reference { StorageView storage_view = MakeStorageView(); - const auto n = storage_view.size; + const SizeType n = storage_view.size; if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) { // Fast path; new element fits. Pointer last_ptr = storage_view.data + n; diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc index 24cc0130..d6832eaf 100644 --- a/absl/debugging/internal/elf_mem_image.cc +++ b/absl/debugging/internal/elf_mem_image.cc @@ -22,6 +22,7 @@ #include #include #include +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" // From binutils/include/elf/common.h (this doesn't appear to be documented @@ -43,11 +44,11 @@ namespace debugging_internal { namespace { -#if __WORDSIZE == 32 +#if __SIZEOF_POINTER__ == 4 const int kElfClass = ELFCLASS32; int ElfBind(const ElfW(Sym) *symbol) { return ELF32_ST_BIND(symbol->st_info); } int ElfType(const ElfW(Sym) *symbol) { return ELF32_ST_TYPE(symbol->st_info); } -#elif __WORDSIZE == 64 +#elif __SIZEOF_POINTER__ == 8 const int kElfClass = ELFCLASS64; int ElfBind(const ElfW(Sym) *symbol) { return ELF64_ST_BIND(symbol->st_info); } int ElfType(const ElfW(Sym) *symbol) { return ELF64_ST_TYPE(symbol->st_info); } @@ -175,17 +176,17 @@ void ElfMemImage::Init(const void *base) { } switch (base_as_char[EI_DATA]) { case ELFDATA2LSB: { - if (__LITTLE_ENDIAN != __BYTE_ORDER) { - assert(false); - return; - } +#ifndef ABSL_IS_LITTLE_ENDIAN + assert(false); + return; +#endif break; } case ELFDATA2MSB: { - if (__BIG_ENDIAN != __BYTE_ORDER) { - assert(false); - return; - } +#ifndef ABSL_IS_BIG_ENDIAN + assert(false); + return; +#endif break; } default: { diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index 46bfade3..86474819 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -31,8 +31,8 @@ #error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set #endif -#if defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \ - !defined(__asmjs__) && !defined(__wasm__) +#if defined(__ELF__) && !defined(__native_client__) && !defined(__asmjs__) && \ + !defined(__wasm__) #define ABSL_HAVE_ELF_MEM_IMAGE 1 #endif diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc index 6be16d90..0dfe9ca6 100644 --- a/absl/debugging/internal/vdso_support.cc +++ b/absl/debugging/internal/vdso_support.cc @@ -20,12 +20,25 @@ #ifdef ABSL_HAVE_VDSO_SUPPORT // defined in vdso_support.h +#if !defined(__has_include) +#define __has_include(header) 0 +#endif + #include #include +#if __has_include() +#include +#elif __has_include() #include +#endif #include -#if __GLIBC_PREREQ(2, 16) // GLIBC-2.16 implements getauxval. +#if defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16)) +#define ABSL_HAVE_GETAUXVAL +#endif + +#ifdef ABSL_HAVE_GETAUXVAL #include #endif @@ -65,7 +78,7 @@ VDSOSupport::VDSOSupport() // the operation should be idempotent. const void *VDSOSupport::Init() { const auto kInvalidBase = debugging_internal::ElfMemImage::kInvalidBase; -#if __GLIBC_PREREQ(2, 16) +#ifdef ABSL_HAVE_GETAUXVAL if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { errno = 0; const void *const sysinfo_ehdr = @@ -74,7 +87,7 @@ const void *VDSOSupport::Init() { vdso_base_.store(sysinfo_ehdr, std::memory_order_relaxed); } } -#endif // __GLIBC_PREREQ(2, 16) +#endif // ABSL_HAVE_GETAUXVAL if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { int fd = open("/proc/self/auxv", O_RDONLY); if (fd == -1) { diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index 966d94bd..cbd84c91 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc @@ -505,7 +505,7 @@ size_t numbers_internal::SixDigitsToBuffer(double d, char* const buffer) { *out++ = '-'; d = -d; } - if (std::isinf(d)) { + if (d > std::numeric_limits::max()) { strcpy(out, "inf"); // NOLINT(runtime/printf) return out + 3 - buffer; } -- cgit v1.2.3 From a59b4daa07a14326d2ceb28cc6d0e079feea3338 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 6 Oct 2021 17:55:30 -0700 Subject: Export of internal Abseil changes -- 17141711ee419daa597a9f31e73721f80143e55a by Gennadiy Rozental : Import of CCTZ from GitHub. PiperOrigin-RevId: 401384949 -- ac48584a7b16e8a12e26d49deb6cddec584a20b5 by Derek Mauro : Internal change PiperOrigin-RevId: 401337785 -- 8a51bb7c962845e0707240c5ba12c1b80f6fbbe9 by Derek Mauro : Internal change PiperOrigin-RevId: 401047691 -- 8e18024510869247f3c04c7807c93709eca2322a by Chris Kennelly : Note that SpinLock does not guarantee priorities for wakeups. PiperOrigin-RevId: 400999238 -- 75bc09b5f95fbb74b74d14c370bfb80011e8fb7f by Derek Mauro : Add visibility restrictions to some internal targets PiperOrigin-RevId: 400718253 -- 1de5061016bc42cd7be009c9725ed2343ce12e3d by Abseil Team : Make it clear that operator<< can also be used in place of ToString when logging absl::Status. PiperOrigin-RevId: 400248269 -- cda15d9dc6e5cd569de7e5e73f409b72a3caed51 by Abseil Team : Minor cleanup PiperOrigin-RevId: 400087535 -- b001375ec47da3a0434be9ca9a45c0df510e7dda by Abseil Team : Move periodic_sampler from base/internal to profiling/internal PiperOrigin-RevId: 400038533 -- e7e02e686abc3900e723080849a3607d190ef57f by Abseil Team : Move exponential_biased from base/internal to profiling/internal PiperOrigin-RevId: 400020329 GitOrigin-RevId: 17141711ee419daa597a9f31e73721f80143e55a Change-Id: I10924df7e1cc198447813dbe97a374a5cef66b49 --- CMake/AbseilDll.cmake | 8 +- absl/base/BUILD.bazel | 69 ------- absl/base/CMakeLists.txt | 54 ------ absl/base/internal/exponential_biased.cc | 93 --------- absl/base/internal/exponential_biased.h | 130 ------------- absl/base/internal/exponential_biased_test.cc | 199 ------------------- absl/base/internal/periodic_sampler.cc | 53 ------ absl/base/internal/periodic_sampler.h | 211 --------------------- absl/base/internal/periodic_sampler_benchmark.cc | 79 -------- absl/base/internal/periodic_sampler_test.cc | 177 ----------------- absl/base/internal/spinlock.h | 4 +- absl/base/internal/spinlock_wait.h | 2 + absl/container/BUILD.bazel | 2 +- absl/container/internal/hashtablez_sampler.cc | 4 +- absl/debugging/BUILD.bazel | 2 + absl/profiling/BUILD.bazel | 73 +++++++ absl/profiling/CMakeLists.txt | 54 ++++++ absl/profiling/internal/exponential_biased.cc | 93 +++++++++ absl/profiling/internal/exponential_biased.h | 130 +++++++++++++ absl/profiling/internal/exponential_biased_test.cc | 199 +++++++++++++++++++ absl/profiling/internal/periodic_sampler.cc | 53 ++++++ absl/profiling/internal/periodic_sampler.h | 211 +++++++++++++++++++++ .../internal/periodic_sampler_benchmark.cc | 79 ++++++++ absl/profiling/internal/periodic_sampler_test.cc | 177 +++++++++++++++++ absl/status/status.h | 2 +- absl/strings/BUILD.bazel | 2 +- absl/strings/internal/cordz_functions.cc | 4 +- absl/synchronization/mutex_test.cc | 55 +++--- absl/time/internal/cctz/src/cctz_benchmark.cc | 1 + .../internal/cctz/src/time_zone_lookup_test.cc | 1 + absl/time/internal/cctz/testdata/version | 2 +- .../cctz/testdata/zoneinfo/Atlantic/Jan_Mayen | Bin 705 -> 676 bytes 32 files changed, 1118 insertions(+), 1105 deletions(-) delete mode 100644 absl/base/internal/exponential_biased.cc delete mode 100644 absl/base/internal/exponential_biased.h delete mode 100644 absl/base/internal/exponential_biased_test.cc delete mode 100644 absl/base/internal/periodic_sampler.cc delete mode 100644 absl/base/internal/periodic_sampler.h delete mode 100644 absl/base/internal/periodic_sampler_benchmark.cc delete mode 100644 absl/base/internal/periodic_sampler_test.cc create mode 100644 absl/profiling/internal/exponential_biased.cc create mode 100644 absl/profiling/internal/exponential_biased.h create mode 100644 absl/profiling/internal/exponential_biased_test.cc create mode 100644 absl/profiling/internal/periodic_sampler.cc create mode 100644 absl/profiling/internal/periodic_sampler.h create mode 100644 absl/profiling/internal/periodic_sampler_benchmark.cc create mode 100644 absl/profiling/internal/periodic_sampler_test.cc (limited to 'absl/debugging') diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 056343e5..fa323ff8 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -17,8 +17,6 @@ set(ABSL_INTERNAL_DLL_FILES "base/internal/dynamic_annotations.h" "base/internal/endian.h" "base/internal/errno_saver.h" - "base/internal/exponential_biased.cc" - "base/internal/exponential_biased.h" "base/internal/fast_type_id.h" "base/internal/hide_ptr.h" "base/internal/identity.h" @@ -28,8 +26,6 @@ set(ABSL_INTERNAL_DLL_FILES "base/internal/low_level_alloc.h" "base/internal/low_level_scheduling.h" "base/internal/per_thread_tls.h" - "base/internal/periodic_sampler.cc" - "base/internal/periodic_sampler.h" "base/internal/pretty_function.h" "base/internal/raw_logging.cc" "base/internal/raw_logging.h" @@ -133,6 +129,10 @@ set(ABSL_INTERNAL_DLL_FILES "numeric/int128.h" "numeric/internal/bits.h" "numeric/internal/representation.h" + "profiling/internal/exponential_biased.cc" + "profiling/internal/exponential_biased.h" + "profiling/internal/periodic_sampler.cc" + "profiling/internal/periodic_sampler.h" "profiling/internal/sample_recorder.h" "random/bernoulli_distribution.h" "random/beta_distribution.h" diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 65ff0dde..8b09b6e3 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -593,75 +593,6 @@ cc_test( ], ) -cc_library( - name = "exponential_biased", - srcs = ["internal/exponential_biased.cc"], - hdrs = ["internal/exponential_biased.h"], - linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl:__subpackages__", - ], - deps = [ - ":config", - ":core_headers", - ], -) - -cc_test( - name = "exponential_biased_test", - size = "small", - srcs = ["internal/exponential_biased_test.cc"], - copts = ABSL_TEST_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = ["//visibility:private"], - deps = [ - ":exponential_biased", - "//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "periodic_sampler", - srcs = ["internal/periodic_sampler.cc"], - hdrs = ["internal/periodic_sampler.h"], - copts = ABSL_DEFAULT_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - deps = [ - ":core_headers", - ":exponential_biased", - ], -) - -cc_test( - name = "periodic_sampler_test", - size = "small", - srcs = ["internal/periodic_sampler_test.cc"], - copts = ABSL_TEST_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = ["//visibility:private"], - deps = [ - ":core_headers", - ":periodic_sampler", - "@com_google_googletest//:gtest_main", - ], -) - -cc_binary( - name = "periodic_sampler_benchmark", - testonly = 1, - srcs = ["internal/periodic_sampler_benchmark.cc"], - copts = ABSL_TEST_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - tags = ["benchmark"], - visibility = ["//visibility:private"], - deps = [ - ":core_headers", - ":periodic_sampler", - "@com_github_google_benchmark//:benchmark_main", - ], -) - cc_library( name = "scoped_set_env", testonly = 1, diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 7d56aa13..c7233cb3 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -519,60 +519,6 @@ absl_cc_test( GTest::gtest_main ) -absl_cc_library( - NAME - exponential_biased - SRCS - "internal/exponential_biased.cc" - HDRS - "internal/exponential_biased.h" - COPTS - ${ABSL_DEFAULT_COPTS} - DEPS - absl::config - absl::core_headers -) - -absl_cc_test( - NAME - exponential_biased_test - SRCS - "internal/exponential_biased_test.cc" - COPTS - ${ABSL_TEST_COPTS} - DEPS - absl::exponential_biased - absl::strings - GTest::gmock_main -) - -absl_cc_library( - NAME - periodic_sampler - SRCS - "internal/periodic_sampler.cc" - HDRS - "internal/periodic_sampler.h" - COPTS - ${ABSL_DEFAULT_COPTS} - DEPS - absl::core_headers - absl::exponential_biased -) - -absl_cc_test( - NAME - periodic_sampler_test - SRCS - "internal/periodic_sampler_test.cc" - COPTS - ${ABSL_TEST_COPTS} - DEPS - absl::core_headers - absl::periodic_sampler - GTest::gmock_main -) - absl_cc_library( NAME scoped_set_env diff --git a/absl/base/internal/exponential_biased.cc b/absl/base/internal/exponential_biased.cc deleted file mode 100644 index 05aeea56..00000000 --- a/absl/base/internal/exponential_biased.cc +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/base/internal/exponential_biased.h" - -#include - -#include -#include -#include -#include - -#include "absl/base/attributes.h" -#include "absl/base/optimization.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { - -// The algorithm generates a random number between 0 and 1 and applies the -// inverse cumulative distribution function for an exponential. Specifically: -// Let m be the inverse of the sample period, then the probability -// distribution function is m*exp(-mx) so the CDF is -// p = 1 - exp(-mx), so -// q = 1 - p = exp(-mx) -// log_e(q) = -mx -// -log_e(q)/m = x -// log_2(q) * (-log_e(2) * 1/m) = x -// In the code, q is actually in the range 1 to 2**26, hence the -26 below -int64_t ExponentialBiased::GetSkipCount(int64_t mean) { - if (ABSL_PREDICT_FALSE(!initialized_)) { - Initialize(); - } - - uint64_t rng = NextRandom(rng_); - rng_ = rng; - - // Take the top 26 bits as the random number - // (This plus the 1<<58 sampling bound give a max possible step of - // 5194297183973780480 bytes.) - // The uint32_t cast is to prevent a (hard-to-reproduce) NAN - // under piii debug for some binaries. - double q = static_cast(rng >> (kPrngNumBits - 26)) + 1.0; - // Put the computed p-value through the CDF of a geometric. - double interval = bias_ + (std::log2(q) - 26) * (-std::log(2.0) * mean); - // Very large values of interval overflow int64_t. To avoid that, we will - // cheat and clamp any huge values to (int64_t max)/2. This is a potential - // source of bias, but the mean would need to be such a large value that it's - // not likely to come up. For example, with a mean of 1e18, the probability of - // hitting this condition is about 1/1000. For a mean of 1e17, standard - // calculators claim that this event won't happen. - if (interval > static_cast(std::numeric_limits::max() / 2)) { - // Assume huge values are bias neutral, retain bias for next call. - return std::numeric_limits::max() / 2; - } - double value = std::rint(interval); - bias_ = interval - value; - return value; -} - -int64_t ExponentialBiased::GetStride(int64_t mean) { - return GetSkipCount(mean - 1) + 1; -} - -void ExponentialBiased::Initialize() { - // We don't get well distributed numbers from `this` so we call NextRandom() a - // bunch to mush the bits around. We use a global_rand to handle the case - // where the same thread (by memory address) gets created and destroyed - // repeatedly. - ABSL_CONST_INIT static std::atomic global_rand(0); - uint64_t r = reinterpret_cast(this) + - global_rand.fetch_add(1, std::memory_order_relaxed); - for (int i = 0; i < 20; ++i) { - r = NextRandom(r); - } - rng_ = r; - initialized_ = true; -} - -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl diff --git a/absl/base/internal/exponential_biased.h b/absl/base/internal/exponential_biased.h deleted file mode 100644 index a81f10e2..00000000 --- a/absl/base/internal/exponential_biased.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_ -#define ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_ - -#include - -#include "absl/base/config.h" -#include "absl/base/macros.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { - -// ExponentialBiased provides a small and fast random number generator for a -// rounded exponential distribution. This generator manages very little state, -// and imposes no synchronization overhead. This makes it useful in specialized -// scenarios requiring minimum overhead, such as stride based periodic sampling. -// -// ExponentialBiased provides two closely related functions, GetSkipCount() and -// GetStride(), both returning a rounded integer defining a number of events -// required before some event with a given mean probability occurs. -// -// The distribution is useful to generate a random wait time or some periodic -// event with a given mean probability. For example, if an action is supposed to -// happen on average once every 'N' events, then we can get a random 'stride' -// counting down how long before the event to happen. For example, if we'd want -// to sample one in every 1000 'Frobber' calls, our code could look like this: -// -// Frobber::Frobber() { -// stride_ = exponential_biased_.GetStride(1000); -// } -// -// void Frobber::Frob(int arg) { -// if (--stride == 0) { -// SampleFrob(arg); -// stride_ = exponential_biased_.GetStride(1000); -// } -// ... -// } -// -// The rounding of the return value creates a bias, especially for smaller means -// where the distribution of the fraction is not evenly distributed. We correct -// this bias by tracking the fraction we rounded up or down on each iteration, -// effectively tracking the distance between the cumulative value, and the -// rounded cumulative value. For example, given a mean of 2: -// -// raw = 1.63076, cumulative = 1.63076, rounded = 2, bias = -0.36923 -// raw = 0.14624, cumulative = 1.77701, rounded = 2, bias = 0.14624 -// raw = 4.93194, cumulative = 6.70895, rounded = 7, bias = -0.06805 -// raw = 0.24206, cumulative = 6.95101, rounded = 7, bias = 0.24206 -// etc... -// -// Adjusting with rounding bias is relatively trivial: -// -// double value = bias_ + exponential_distribution(mean)(); -// double rounded_value = std::rint(value); -// bias_ = value - rounded_value; -// return rounded_value; -// -// This class is thread-compatible. -class ExponentialBiased { - public: - // The number of bits set by NextRandom. - static constexpr int kPrngNumBits = 48; - - // `GetSkipCount()` returns the number of events to skip before some chosen - // event happens. For example, randomly tossing a coin, we will on average - // throw heads once before we get tails. We can simulate random coin tosses - // using GetSkipCount() as: - // - // ExponentialBiased eb; - // for (...) { - // int number_of_heads_before_tail = eb.GetSkipCount(1); - // for (int flips = 0; flips < number_of_heads_before_tail; ++flips) { - // printf("head..."); - // } - // printf("tail\n"); - // } - // - int64_t GetSkipCount(int64_t mean); - - // GetStride() returns the number of events required for a specific event to - // happen. See the class comments for a usage example. `GetStride()` is - // equivalent to `GetSkipCount(mean - 1) + 1`. When to use `GetStride()` or - // `GetSkipCount()` depends mostly on what best fits the use case. - int64_t GetStride(int64_t mean); - - // Computes a random number in the range [0, 1<<(kPrngNumBits+1) - 1] - // - // This is public to enable testing. - static uint64_t NextRandom(uint64_t rnd); - - private: - void Initialize(); - - uint64_t rng_{0}; - double bias_{0}; - bool initialized_{false}; -}; - -// Returns the next prng value. -// pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48 -// This is the lrand64 generator. -inline uint64_t ExponentialBiased::NextRandom(uint64_t rnd) { - const uint64_t prng_mult = uint64_t{0x5DEECE66D}; - const uint64_t prng_add = 0xB; - const uint64_t prng_mod_power = 48; - const uint64_t prng_mod_mask = - ~((~static_cast(0)) << prng_mod_power); - return (prng_mult * rnd + prng_add) & prng_mod_mask; -} - -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_ diff --git a/absl/base/internal/exponential_biased_test.cc b/absl/base/internal/exponential_biased_test.cc deleted file mode 100644 index 075583ca..00000000 --- a/absl/base/internal/exponential_biased_test.cc +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/base/internal/exponential_biased.h" - -#include - -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/strings/str_cat.h" - -using ::testing::Ge; - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { - -MATCHER_P2(IsBetween, a, b, - absl::StrCat(std::string(negation ? "isn't" : "is"), " between ", a, - " and ", b)) { - return a <= arg && arg <= b; -} - -// Tests of the quality of the random numbers generated -// This uses the Anderson Darling test for uniformity. -// See "Evaluating the Anderson-Darling Distribution" by Marsaglia -// for details. - -// Short cut version of ADinf(z), z>0 (from Marsaglia) -// This returns the p-value for Anderson Darling statistic in -// the limit as n-> infinity. For finite n, apply the error fix below. -double AndersonDarlingInf(double z) { - if (z < 2) { - return exp(-1.2337141 / z) / sqrt(z) * - (2.00012 + - (0.247105 - - (0.0649821 - (0.0347962 - (0.011672 - 0.00168691 * z) * z) * z) * - z) * - z); - } - return exp( - -exp(1.0776 - - (2.30695 - - (0.43424 - (0.082433 - (0.008056 - 0.0003146 * z) * z) * z) * z) * - z)); -} - -// Corrects the approximation error in AndersonDarlingInf for small values of n -// Add this to AndersonDarlingInf to get a better approximation -// (from Marsaglia) -double AndersonDarlingErrFix(int n, double x) { - if (x > 0.8) { - return (-130.2137 + - (745.2337 - - (1705.091 - (1950.646 - (1116.360 - 255.7844 * x) * x) * x) * x) * - x) / - n; - } - double cutoff = 0.01265 + 0.1757 / n; - if (x < cutoff) { - double t = x / cutoff; - t = sqrt(t) * (1 - t) * (49 * t - 102); - return t * (0.0037 / (n * n) + 0.00078 / n + 0.00006) / n; - } else { - double t = (x - cutoff) / (0.8 - cutoff); - t = -0.00022633 + - (6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864 * t) * t) * t) * t) * - t; - return t * (0.04213 + 0.01365 / n) / n; - } -} - -// Returns the AndersonDarling p-value given n and the value of the statistic -double AndersonDarlingPValue(int n, double z) { - double ad = AndersonDarlingInf(z); - double errfix = AndersonDarlingErrFix(n, ad); - return ad + errfix; -} - -double AndersonDarlingStatistic(const std::vector& random_sample) { - int n = random_sample.size(); - double ad_sum = 0; - for (int i = 0; i < n; i++) { - ad_sum += (2 * i + 1) * - std::log(random_sample[i] * (1 - random_sample[n - 1 - i])); - } - double ad_statistic = -n - 1 / static_cast(n) * ad_sum; - return ad_statistic; -} - -// Tests if the array of doubles is uniformly distributed. -// Returns the p-value of the Anderson Darling Statistic -// for the given set of sorted random doubles -// See "Evaluating the Anderson-Darling Distribution" by -// Marsaglia and Marsaglia for details. -double AndersonDarlingTest(const std::vector& random_sample) { - double ad_statistic = AndersonDarlingStatistic(random_sample); - double p = AndersonDarlingPValue(random_sample.size(), ad_statistic); - return p; -} - -TEST(ExponentialBiasedTest, CoinTossDemoWithGetSkipCount) { - ExponentialBiased eb; - for (int runs = 0; runs < 10; ++runs) { - for (int flips = eb.GetSkipCount(1); flips > 0; --flips) { - printf("head..."); - } - printf("tail\n"); - } - int heads = 0; - for (int i = 0; i < 10000000; i += 1 + eb.GetSkipCount(1)) { - ++heads; - } - printf("Heads = %d (%f%%)\n", heads, 100.0 * heads / 10000000); -} - -TEST(ExponentialBiasedTest, SampleDemoWithStride) { - ExponentialBiased eb; - int stride = eb.GetStride(10); - int samples = 0; - for (int i = 0; i < 10000000; ++i) { - if (--stride == 0) { - ++samples; - stride = eb.GetStride(10); - } - } - printf("Samples = %d (%f%%)\n", samples, 100.0 * samples / 10000000); -} - - -// Testing that NextRandom generates uniform random numbers. Applies the -// Anderson-Darling test for uniformity -TEST(ExponentialBiasedTest, TestNextRandom) { - for (auto n : std::vector({ - 10, // Check short-range correlation - 100, 1000, - 10000 // Make sure there's no systemic error - })) { - uint64_t x = 1; - // This assumes that the prng returns 48 bit numbers - uint64_t max_prng_value = static_cast(1) << 48; - // Initialize. - for (int i = 1; i <= 20; i++) { - x = ExponentialBiased::NextRandom(x); - } - std::vector int_random_sample(n); - // Collect samples - for (int i = 0; i < n; i++) { - int_random_sample[i] = x; - x = ExponentialBiased::NextRandom(x); - } - // First sort them... - std::sort(int_random_sample.begin(), int_random_sample.end()); - std::vector random_sample(n); - // Convert them to uniform randoms (in the range [0,1]) - for (int i = 0; i < n; i++) { - random_sample[i] = - static_cast(int_random_sample[i]) / max_prng_value; - } - // Now compute the Anderson-Darling statistic - double ad_pvalue = AndersonDarlingTest(random_sample); - EXPECT_GT(std::min(ad_pvalue, 1 - ad_pvalue), 0.0001) - << "prng is not uniform: n = " << n << " p = " << ad_pvalue; - } -} - -// The generator needs to be available as a thread_local and as a static -// variable. -TEST(ExponentialBiasedTest, InitializationModes) { - ABSL_CONST_INIT static ExponentialBiased eb_static; - EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0)); - -#ifdef ABSL_HAVE_THREAD_LOCAL - thread_local ExponentialBiased eb_thread; - EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0)); -#endif - - ExponentialBiased eb_stack; - EXPECT_THAT(eb_stack.GetSkipCount(2), Ge(0)); -} - -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl diff --git a/absl/base/internal/periodic_sampler.cc b/absl/base/internal/periodic_sampler.cc deleted file mode 100644 index 520dabba..00000000 --- a/absl/base/internal/periodic_sampler.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/base/internal/periodic_sampler.h" - -#include - -#include "absl/base/internal/exponential_biased.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { - -int64_t PeriodicSamplerBase::GetExponentialBiased(int period) noexcept { - return rng_.GetStride(period); -} - -bool PeriodicSamplerBase::SubtleConfirmSample() noexcept { - int current_period = period(); - - // Deal with period case 0 (always off) and 1 (always on) - if (ABSL_PREDICT_FALSE(current_period < 2)) { - stride_ = 0; - return current_period == 1; - } - - // Check if this is the first call to Sample() - if (ABSL_PREDICT_FALSE(stride_ == 1)) { - stride_ = static_cast(-GetExponentialBiased(current_period)); - if (static_cast(stride_) < -1) { - ++stride_; - return false; - } - } - - stride_ = static_cast(-GetExponentialBiased(current_period)); - return true; -} - -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl diff --git a/absl/base/internal/periodic_sampler.h b/absl/base/internal/periodic_sampler.h deleted file mode 100644 index f8a86796..00000000 --- a/absl/base/internal/periodic_sampler.h +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_ -#define ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_ - -#include - -#include - -#include "absl/base/internal/exponential_biased.h" -#include "absl/base/optimization.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { - -// PeriodicSamplerBase provides the basic period sampler implementation. -// -// This is the base class for the templated PeriodicSampler class, which holds -// a global std::atomic value identified by a user defined tag, such that -// each specific PeriodSampler implementation holds its own global period. -// -// PeriodicSamplerBase is thread-compatible except where stated otherwise. -class PeriodicSamplerBase { - public: - // PeriodicSamplerBase is trivial / copyable / movable / destructible. - PeriodicSamplerBase() = default; - PeriodicSamplerBase(PeriodicSamplerBase&&) = default; - PeriodicSamplerBase(const PeriodicSamplerBase&) = default; - - // Returns true roughly once every `period` calls. This is established by a - // randomly picked `stride` that is counted down on each call to `Sample`. - // This stride is picked such that the probability of `Sample()` returning - // true is 1 in `period`. - inline bool Sample() noexcept; - - // The below methods are intended for optimized use cases where the - // size of the inlined fast path code is highly important. Applications - // should use the `Sample()` method unless they have proof that their - // specific use case requires the optimizations offered by these methods. - // - // An example of such a use case is SwissTable sampling. All sampling checks - // are in inlined SwissTable methods, and the number of call sites is huge. - // In this case, the inlined code size added to each translation unit calling - // SwissTable methods is non-trivial. - // - // The `SubtleMaybeSample()` function spuriously returns true even if the - // function should not be sampled, applications MUST match each call to - // 'SubtleMaybeSample()' returning true with a `SubtleConfirmSample()` call, - // and use the result of the latter as the sampling decision. - // In other words: the code should logically be equivalent to: - // - // if (SubtleMaybeSample() && SubtleConfirmSample()) { - // // Sample this call - // } - // - // In the 'inline-size' optimized case, the `SubtleConfirmSample()` call can - // be placed out of line, for example, the typical use case looks as follows: - // - // // --- frobber.h ----------- - // void FrobberSampled(); - // - // inline void FrobberImpl() { - // // ... - // } - // - // inline void Frobber() { - // if (ABSL_PREDICT_FALSE(sampler.SubtleMaybeSample())) { - // FrobberSampled(); - // } else { - // FrobberImpl(); - // } - // } - // - // // --- frobber.cc ----------- - // void FrobberSampled() { - // if (!sampler.SubtleConfirmSample())) { - // // Spurious false positive - // FrobberImpl(); - // return; - // } - // - // // Sampled execution - // // ... - // } - inline bool SubtleMaybeSample() noexcept; - bool SubtleConfirmSample() noexcept; - - protected: - // We explicitly don't use a virtual destructor as this class is never - // virtually destroyed, and it keeps the class trivial, which avoids TLS - // prologue and epilogue code for our TLS instances. - ~PeriodicSamplerBase() = default; - - // Returns the next stride for our sampler. - // This function is virtual for testing purposes only. - virtual int64_t GetExponentialBiased(int period) noexcept; - - private: - // Returns the current period of this sampler. Thread-safe. - virtual int period() const noexcept = 0; - - // Keep and decrement stride_ as an unsigned integer, but compare the value - // to zero casted as a signed int. clang and msvc do not create optimum code - // if we use signed for the combined decrement and sign comparison. - // - // Below 3 alternative options, all compiles generate the best code - // using the unsigned increment <---> signed int comparison option. - // - // Option 1: - // int64_t stride_; - // if (ABSL_PREDICT_TRUE(++stride_ < 0)) { ... } - // - // GCC x64 (OK) : https://gcc.godbolt.org/z/R5MzzA - // GCC ppc (OK) : https://gcc.godbolt.org/z/z7NZAt - // Clang x64 (BAD): https://gcc.godbolt.org/z/t4gPsd - // ICC x64 (OK) : https://gcc.godbolt.org/z/rE6s8W - // MSVC x64 (OK) : https://gcc.godbolt.org/z/ARMXqS - // - // Option 2: - // int64_t stride_ = 0; - // if (ABSL_PREDICT_TRUE(--stride_ >= 0)) { ... } - // - // GCC x64 (OK) : https://gcc.godbolt.org/z/jSQxYK - // GCC ppc (OK) : https://gcc.godbolt.org/z/VJdYaA - // Clang x64 (BAD): https://gcc.godbolt.org/z/Xm4NjX - // ICC x64 (OK) : https://gcc.godbolt.org/z/4snaFd - // MSVC x64 (BAD): https://gcc.godbolt.org/z/BgnEKE - // - // Option 3: - // uint64_t stride_; - // if (ABSL_PREDICT_TRUE(static_cast(++stride_) < 0)) { ... } - // - // GCC x64 (OK) : https://gcc.godbolt.org/z/bFbfPy - // GCC ppc (OK) : https://gcc.godbolt.org/z/S9KkUE - // Clang x64 (OK) : https://gcc.godbolt.org/z/UYzRb4 - // ICC x64 (OK) : https://gcc.godbolt.org/z/ptTNfD - // MSVC x64 (OK) : https://gcc.godbolt.org/z/76j4-5 - uint64_t stride_ = 0; - ExponentialBiased rng_; -}; - -inline bool PeriodicSamplerBase::SubtleMaybeSample() noexcept { - // See comments on `stride_` for the unsigned increment / signed compare. - if (ABSL_PREDICT_TRUE(static_cast(++stride_) < 0)) { - return false; - } - return true; -} - -inline bool PeriodicSamplerBase::Sample() noexcept { - return ABSL_PREDICT_FALSE(SubtleMaybeSample()) ? SubtleConfirmSample() - : false; -} - -// PeriodicSampler is a concreted periodic sampler implementation. -// The user provided Tag identifies the implementation, and is required to -// isolate the global state of this instance from other instances. -// -// Typical use case: -// -// struct HashTablezTag {}; -// thread_local PeriodicSampler sampler; -// -// void HashTableSamplingLogic(...) { -// if (sampler.Sample()) { -// HashTableSlowSamplePath(...); -// } -// } -// -template -class PeriodicSampler final : public PeriodicSamplerBase { - public: - ~PeriodicSampler() = default; - - int period() const noexcept final { - return period_.load(std::memory_order_relaxed); - } - - // Sets the global period for this sampler. Thread-safe. - // Setting a period of 0 disables the sampler, i.e., every call to Sample() - // will return false. Setting a period of 1 puts the sampler in 'always on' - // mode, i.e., every call to Sample() returns true. - static void SetGlobalPeriod(int period) { - period_.store(period, std::memory_order_relaxed); - } - - private: - static std::atomic period_; -}; - -template -std::atomic PeriodicSampler::period_(default_period); - -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_ diff --git a/absl/base/internal/periodic_sampler_benchmark.cc b/absl/base/internal/periodic_sampler_benchmark.cc deleted file mode 100644 index 5ad469ce..00000000 --- a/absl/base/internal/periodic_sampler_benchmark.cc +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "benchmark/benchmark.h" -#include "absl/base/internal/periodic_sampler.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { -namespace { - -template -void BM_Sample(Sampler* sampler, benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(sampler); - benchmark::DoNotOptimize(sampler->Sample()); - } -} - -template -void BM_SampleMinunumInlined(Sampler* sampler, benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(sampler); - if (ABSL_PREDICT_FALSE(sampler->SubtleMaybeSample())) { - benchmark::DoNotOptimize(sampler->SubtleConfirmSample()); - } - } -} - -void BM_PeriodicSampler_TinySample(benchmark::State& state) { - struct Tag {}; - PeriodicSampler sampler; - BM_Sample(&sampler, state); -} -BENCHMARK(BM_PeriodicSampler_TinySample); - -void BM_PeriodicSampler_ShortSample(benchmark::State& state) { - struct Tag {}; - PeriodicSampler sampler; - BM_Sample(&sampler, state); -} -BENCHMARK(BM_PeriodicSampler_ShortSample); - -void BM_PeriodicSampler_LongSample(benchmark::State& state) { - struct Tag {}; - PeriodicSampler sampler; - BM_Sample(&sampler, state); -} -BENCHMARK(BM_PeriodicSampler_LongSample); - -void BM_PeriodicSampler_LongSampleMinunumInlined(benchmark::State& state) { - struct Tag {}; - PeriodicSampler sampler; - BM_SampleMinunumInlined(&sampler, state); -} -BENCHMARK(BM_PeriodicSampler_LongSampleMinunumInlined); - -void BM_PeriodicSampler_Disabled(benchmark::State& state) { - struct Tag {}; - PeriodicSampler sampler; - BM_Sample(&sampler, state); -} -BENCHMARK(BM_PeriodicSampler_Disabled); - -} // namespace -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl diff --git a/absl/base/internal/periodic_sampler_test.cc b/absl/base/internal/periodic_sampler_test.cc deleted file mode 100644 index 3b301e37..00000000 --- a/absl/base/internal/periodic_sampler_test.cc +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/base/internal/periodic_sampler.h" - -#include // NOLINT(build/c++11) - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/base/attributes.h" -#include "absl/base/macros.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { -namespace { - -using testing::Eq; -using testing::Return; -using testing::StrictMock; - -class MockPeriodicSampler : public PeriodicSamplerBase { - public: - virtual ~MockPeriodicSampler() = default; - - MOCK_METHOD(int, period, (), (const, noexcept)); - MOCK_METHOD(int64_t, GetExponentialBiased, (int), (noexcept)); -}; - -TEST(PeriodicSamplerBaseTest, Sample) { - StrictMock sampler; - - EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(16)); - EXPECT_CALL(sampler, GetExponentialBiased(16)) - .WillOnce(Return(2)) - .WillOnce(Return(3)) - .WillOnce(Return(4)); - - EXPECT_FALSE(sampler.Sample()); - EXPECT_TRUE(sampler.Sample()); - - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); - EXPECT_TRUE(sampler.Sample()); - - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); -} - -TEST(PeriodicSamplerBaseTest, ImmediatelySample) { - StrictMock sampler; - - EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16)); - EXPECT_CALL(sampler, GetExponentialBiased(16)) - .WillOnce(Return(1)) - .WillOnce(Return(2)) - .WillOnce(Return(3)); - - EXPECT_TRUE(sampler.Sample()); - - EXPECT_FALSE(sampler.Sample()); - EXPECT_TRUE(sampler.Sample()); - - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); -} - -TEST(PeriodicSamplerBaseTest, Disabled) { - StrictMock sampler; - - EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(0)); - - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); -} - -TEST(PeriodicSamplerBaseTest, AlwaysOn) { - StrictMock sampler; - - EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(1)); - - EXPECT_TRUE(sampler.Sample()); - EXPECT_TRUE(sampler.Sample()); - EXPECT_TRUE(sampler.Sample()); -} - -TEST(PeriodicSamplerBaseTest, Disable) { - StrictMock sampler; - - EXPECT_CALL(sampler, period()).WillOnce(Return(16)); - EXPECT_CALL(sampler, GetExponentialBiased(16)).WillOnce(Return(3)); - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); - - EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(0)); - - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); -} - -TEST(PeriodicSamplerBaseTest, Enable) { - StrictMock sampler; - - EXPECT_CALL(sampler, period()).WillOnce(Return(0)); - EXPECT_FALSE(sampler.Sample()); - - EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16)); - EXPECT_CALL(sampler, GetExponentialBiased(16)) - .Times(2) - .WillRepeatedly(Return(3)); - - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); - EXPECT_TRUE(sampler.Sample()); - - EXPECT_FALSE(sampler.Sample()); - EXPECT_FALSE(sampler.Sample()); -} - -TEST(PeriodicSamplerTest, ConstructConstInit) { - struct Tag {}; - ABSL_CONST_INIT static PeriodicSampler sampler; - (void)sampler; -} - -TEST(PeriodicSamplerTest, DefaultPeriod0) { - struct Tag {}; - PeriodicSampler sampler; - EXPECT_THAT(sampler.period(), Eq(0)); -} - -TEST(PeriodicSamplerTest, DefaultPeriod) { - struct Tag {}; - PeriodicSampler sampler; - EXPECT_THAT(sampler.period(), Eq(100)); -} - -TEST(PeriodicSamplerTest, SetGlobalPeriod) { - struct Tag1 {}; - struct Tag2 {}; - PeriodicSampler sampler1; - PeriodicSampler sampler2; - - EXPECT_THAT(sampler1.period(), Eq(25)); - EXPECT_THAT(sampler2.period(), Eq(50)); - - std::thread thread([] { - PeriodicSampler sampler1; - PeriodicSampler sampler2; - EXPECT_THAT(sampler1.period(), Eq(25)); - EXPECT_THAT(sampler2.period(), Eq(50)); - sampler1.SetGlobalPeriod(10); - sampler2.SetGlobalPeriod(20); - }); - thread.join(); - - EXPECT_THAT(sampler1.period(), Eq(10)); - EXPECT_THAT(sampler2.period(), Eq(20)); -} - -} // namespace -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h index c73b5e09..ac40daff 100644 --- a/absl/base/internal/spinlock.h +++ b/absl/base/internal/spinlock.h @@ -16,13 +16,15 @@ // Most users requiring mutual exclusion should use Mutex. // SpinLock is provided for use in two situations: -// - for use in code that Mutex itself depends on +// - for use by Abseil internal code that Mutex itself depends on // - for async signal safety (see below) // SpinLock is async signal safe. If a spinlock is used within a signal // handler, all code that acquires the lock must ensure that the signal cannot // arrive while they are holding the lock. Typically, this is done by blocking // the signal. +// +// Threads waiting on a SpinLock may be woken in an arbitrary order. #ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_ #define ABSL_BASE_INTERNAL_SPINLOCK_H_ diff --git a/absl/base/internal/spinlock_wait.h b/absl/base/internal/spinlock_wait.h index 579bd09f..9a1adcda 100644 --- a/absl/base/internal/spinlock_wait.h +++ b/absl/base/internal/spinlock_wait.h @@ -39,6 +39,8 @@ struct SpinLockWaitTransition { // satisfying 0<=i *w, int n, const SpinLockWaitTransition trans[], SchedulingMode scheduling_mode); diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index c9d387d6..9e3bc06a 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -510,9 +510,9 @@ cc_library( ":have_sse", "//absl/base", "//absl/base:core_headers", - "//absl/base:exponential_biased", "//absl/debugging:stacktrace", "//absl/memory", + "//absl/profiling:exponential_biased", "//absl/profiling:sample_recorder", "//absl/synchronization", "//absl/utility", diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc index 4b133705..7070912e 100644 --- a/absl/container/internal/hashtablez_sampler.cc +++ b/absl/container/internal/hashtablez_sampler.cc @@ -21,10 +21,10 @@ #include #include "absl/base/attributes.h" -#include "absl/base/internal/exponential_biased.h" #include "absl/container/internal/have_sse.h" #include "absl/debugging/stacktrace.h" #include "absl/memory/memory.h" +#include "absl/profiling/internal/exponential_biased.h" #include "absl/profiling/internal/sample_recorder.h" #include "absl/synchronization/mutex.h" @@ -40,7 +40,7 @@ ABSL_CONST_INIT std::atomic g_hashtablez_enabled{ ABSL_CONST_INIT std::atomic g_hashtablez_sample_parameter{1 << 10}; #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) -ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased +ABSL_PER_THREAD_TLS_KEYWORD absl::profiling_internal::ExponentialBiased g_exponential_biased_generator; #endif diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index b536a044..b503da51 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -183,6 +183,7 @@ cc_library( ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = ["//visibility:private"], deps = [ "//absl/base:config", "//absl/base:core_headers", @@ -197,6 +198,7 @@ cc_library( srcs = ["internal/demangle.cc"], hdrs = ["internal/demangle.h"], copts = ABSL_DEFAULT_COPTS, + visibility = ["//visibility:private"], deps = [ "//absl/base", "//absl/base:config", diff --git a/absl/profiling/BUILD.bazel b/absl/profiling/BUILD.bazel index ba4811b3..496a06b2 100644 --- a/absl/profiling/BUILD.bazel +++ b/absl/profiling/BUILD.bazel @@ -16,6 +16,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_LINKOPTS", + "ABSL_TEST_COPTS", ) package(default_visibility = ["//visibility:private"]) @@ -51,3 +52,75 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_library( + name = "exponential_biased", + srcs = ["internal/exponential_biased.cc"], + hdrs = ["internal/exponential_biased.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = [ + "//absl:__subpackages__", + ], + deps = [ + "//absl/base:config", + "//absl/base:core_headers", + ], +) + +cc_test( + name = "exponential_biased_test", + size = "small", + srcs = ["internal/exponential_biased_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = ["//visibility:private"], + deps = [ + ":exponential_biased", + "//absl/strings", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "periodic_sampler", + srcs = ["internal/periodic_sampler.cc"], + hdrs = ["internal/periodic_sampler.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = [ + "//absl:__subpackages__", + ], + deps = [ + ":exponential_biased", + "//absl/base:core_headers", + ], +) + +cc_test( + name = "periodic_sampler_test", + size = "small", + srcs = ["internal/periodic_sampler_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = ["//visibility:private"], + deps = [ + ":periodic_sampler", + "//absl/base:core_headers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_binary( + name = "periodic_sampler_benchmark", + testonly = 1, + srcs = ["internal/periodic_sampler_benchmark.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + tags = ["benchmark"], + visibility = ["//visibility:private"], + deps = [ + ":periodic_sampler", + "//absl/base:core_headers", + "@com_github_google_benchmark//:benchmark_main", + ], +) diff --git a/absl/profiling/CMakeLists.txt b/absl/profiling/CMakeLists.txt index 7b6a7780..9b3a7102 100644 --- a/absl/profiling/CMakeLists.txt +++ b/absl/profiling/CMakeLists.txt @@ -37,3 +37,57 @@ absl_cc_test( GTest::gmock_main ) +absl_cc_library( + NAME + exponential_biased + SRCS + "internal/exponential_biased.cc" + HDRS + "internal/exponential_biased.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + absl::core_headers +) + +absl_cc_test( + NAME + exponential_biased_test + SRCS + "internal/exponential_biased_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::exponential_biased + absl::strings + GTest::gmock_main +) + +absl_cc_library( + NAME + periodic_sampler + SRCS + "internal/periodic_sampler.cc" + HDRS + "internal/periodic_sampler.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + absl::exponential_biased +) + +absl_cc_test( + NAME + periodic_sampler_test + SRCS + "internal/periodic_sampler_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::core_headers + absl::periodic_sampler + GTest::gmock_main +) + diff --git a/absl/profiling/internal/exponential_biased.cc b/absl/profiling/internal/exponential_biased.cc new file mode 100644 index 00000000..81d9a757 --- /dev/null +++ b/absl/profiling/internal/exponential_biased.cc @@ -0,0 +1,93 @@ +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/profiling/internal/exponential_biased.h" + +#include + +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/optimization.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace profiling_internal { + +// The algorithm generates a random number between 0 and 1 and applies the +// inverse cumulative distribution function for an exponential. Specifically: +// Let m be the inverse of the sample period, then the probability +// distribution function is m*exp(-mx) so the CDF is +// p = 1 - exp(-mx), so +// q = 1 - p = exp(-mx) +// log_e(q) = -mx +// -log_e(q)/m = x +// log_2(q) * (-log_e(2) * 1/m) = x +// In the code, q is actually in the range 1 to 2**26, hence the -26 below +int64_t ExponentialBiased::GetSkipCount(int64_t mean) { + if (ABSL_PREDICT_FALSE(!initialized_)) { + Initialize(); + } + + uint64_t rng = NextRandom(rng_); + rng_ = rng; + + // Take the top 26 bits as the random number + // (This plus the 1<<58 sampling bound give a max possible step of + // 5194297183973780480 bytes.) + // The uint32_t cast is to prevent a (hard-to-reproduce) NAN + // under piii debug for some binaries. + double q = static_cast(rng >> (kPrngNumBits - 26)) + 1.0; + // Put the computed p-value through the CDF of a geometric. + double interval = bias_ + (std::log2(q) - 26) * (-std::log(2.0) * mean); + // Very large values of interval overflow int64_t. To avoid that, we will + // cheat and clamp any huge values to (int64_t max)/2. This is a potential + // source of bias, but the mean would need to be such a large value that it's + // not likely to come up. For example, with a mean of 1e18, the probability of + // hitting this condition is about 1/1000. For a mean of 1e17, standard + // calculators claim that this event won't happen. + if (interval > static_cast(std::numeric_limits::max() / 2)) { + // Assume huge values are bias neutral, retain bias for next call. + return std::numeric_limits::max() / 2; + } + double value = std::rint(interval); + bias_ = interval - value; + return value; +} + +int64_t ExponentialBiased::GetStride(int64_t mean) { + return GetSkipCount(mean - 1) + 1; +} + +void ExponentialBiased::Initialize() { + // We don't get well distributed numbers from `this` so we call NextRandom() a + // bunch to mush the bits around. We use a global_rand to handle the case + // where the same thread (by memory address) gets created and destroyed + // repeatedly. + ABSL_CONST_INIT static std::atomic global_rand(0); + uint64_t r = reinterpret_cast(this) + + global_rand.fetch_add(1, std::memory_order_relaxed); + for (int i = 0; i < 20; ++i) { + r = NextRandom(r); + } + rng_ = r; + initialized_ = true; +} + +} // namespace profiling_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/profiling/internal/exponential_biased.h b/absl/profiling/internal/exponential_biased.h new file mode 100644 index 00000000..d31f7782 --- /dev/null +++ b/absl/profiling/internal/exponential_biased.h @@ -0,0 +1,130 @@ +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_PROFILING_INTERNAL_EXPONENTIAL_BIASED_H_ +#define ABSL_PROFILING_INTERNAL_EXPONENTIAL_BIASED_H_ + +#include + +#include "absl/base/config.h" +#include "absl/base/macros.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace profiling_internal { + +// ExponentialBiased provides a small and fast random number generator for a +// rounded exponential distribution. This generator manages very little state, +// and imposes no synchronization overhead. This makes it useful in specialized +// scenarios requiring minimum overhead, such as stride based periodic sampling. +// +// ExponentialBiased provides two closely related functions, GetSkipCount() and +// GetStride(), both returning a rounded integer defining a number of events +// required before some event with a given mean probability occurs. +// +// The distribution is useful to generate a random wait time or some periodic +// event with a given mean probability. For example, if an action is supposed to +// happen on average once every 'N' events, then we can get a random 'stride' +// counting down how long before the event to happen. For example, if we'd want +// to sample one in every 1000 'Frobber' calls, our code could look like this: +// +// Frobber::Frobber() { +// stride_ = exponential_biased_.GetStride(1000); +// } +// +// void Frobber::Frob(int arg) { +// if (--stride == 0) { +// SampleFrob(arg); +// stride_ = exponential_biased_.GetStride(1000); +// } +// ... +// } +// +// The rounding of the return value creates a bias, especially for smaller means +// where the distribution of the fraction is not evenly distributed. We correct +// this bias by tracking the fraction we rounded up or down on each iteration, +// effectively tracking the distance between the cumulative value, and the +// rounded cumulative value. For example, given a mean of 2: +// +// raw = 1.63076, cumulative = 1.63076, rounded = 2, bias = -0.36923 +// raw = 0.14624, cumulative = 1.77701, rounded = 2, bias = 0.14624 +// raw = 4.93194, cumulative = 6.70895, rounded = 7, bias = -0.06805 +// raw = 0.24206, cumulative = 6.95101, rounded = 7, bias = 0.24206 +// etc... +// +// Adjusting with rounding bias is relatively trivial: +// +// double value = bias_ + exponential_distribution(mean)(); +// double rounded_value = std::rint(value); +// bias_ = value - rounded_value; +// return rounded_value; +// +// This class is thread-compatible. +class ExponentialBiased { + public: + // The number of bits set by NextRandom. + static constexpr int kPrngNumBits = 48; + + // `GetSkipCount()` returns the number of events to skip before some chosen + // event happens. For example, randomly tossing a coin, we will on average + // throw heads once before we get tails. We can simulate random coin tosses + // using GetSkipCount() as: + // + // ExponentialBiased eb; + // for (...) { + // int number_of_heads_before_tail = eb.GetSkipCount(1); + // for (int flips = 0; flips < number_of_heads_before_tail; ++flips) { + // printf("head..."); + // } + // printf("tail\n"); + // } + // + int64_t GetSkipCount(int64_t mean); + + // GetStride() returns the number of events required for a specific event to + // happen. See the class comments for a usage example. `GetStride()` is + // equivalent to `GetSkipCount(mean - 1) + 1`. When to use `GetStride()` or + // `GetSkipCount()` depends mostly on what best fits the use case. + int64_t GetStride(int64_t mean); + + // Computes a random number in the range [0, 1<<(kPrngNumBits+1) - 1] + // + // This is public to enable testing. + static uint64_t NextRandom(uint64_t rnd); + + private: + void Initialize(); + + uint64_t rng_{0}; + double bias_{0}; + bool initialized_{false}; +}; + +// Returns the next prng value. +// pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48 +// This is the lrand64 generator. +inline uint64_t ExponentialBiased::NextRandom(uint64_t rnd) { + const uint64_t prng_mult = uint64_t{0x5DEECE66D}; + const uint64_t prng_add = 0xB; + const uint64_t prng_mod_power = 48; + const uint64_t prng_mod_mask = + ~((~static_cast(0)) << prng_mod_power); + return (prng_mult * rnd + prng_add) & prng_mod_mask; +} + +} // namespace profiling_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_PROFILING_INTERNAL_EXPONENTIAL_BIASED_H_ diff --git a/absl/profiling/internal/exponential_biased_test.cc b/absl/profiling/internal/exponential_biased_test.cc new file mode 100644 index 00000000..5675001d --- /dev/null +++ b/absl/profiling/internal/exponential_biased_test.cc @@ -0,0 +1,199 @@ +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/profiling/internal/exponential_biased.h" + +#include + +#include +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/strings/str_cat.h" + +using ::testing::Ge; + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace profiling_internal { + +MATCHER_P2(IsBetween, a, b, + absl::StrCat(std::string(negation ? "isn't" : "is"), " between ", a, + " and ", b)) { + return a <= arg && arg <= b; +} + +// Tests of the quality of the random numbers generated +// This uses the Anderson Darling test for uniformity. +// See "Evaluating the Anderson-Darling Distribution" by Marsaglia +// for details. + +// Short cut version of ADinf(z), z>0 (from Marsaglia) +// This returns the p-value for Anderson Darling statistic in +// the limit as n-> infinity. For finite n, apply the error fix below. +double AndersonDarlingInf(double z) { + if (z < 2) { + return exp(-1.2337141 / z) / sqrt(z) * + (2.00012 + + (0.247105 - + (0.0649821 - (0.0347962 - (0.011672 - 0.00168691 * z) * z) * z) * + z) * + z); + } + return exp( + -exp(1.0776 - + (2.30695 - + (0.43424 - (0.082433 - (0.008056 - 0.0003146 * z) * z) * z) * z) * + z)); +} + +// Corrects the approximation error in AndersonDarlingInf for small values of n +// Add this to AndersonDarlingInf to get a better approximation +// (from Marsaglia) +double AndersonDarlingErrFix(int n, double x) { + if (x > 0.8) { + return (-130.2137 + + (745.2337 - + (1705.091 - (1950.646 - (1116.360 - 255.7844 * x) * x) * x) * x) * + x) / + n; + } + double cutoff = 0.01265 + 0.1757 / n; + if (x < cutoff) { + double t = x / cutoff; + t = sqrt(t) * (1 - t) * (49 * t - 102); + return t * (0.0037 / (n * n) + 0.00078 / n + 0.00006) / n; + } else { + double t = (x - cutoff) / (0.8 - cutoff); + t = -0.00022633 + + (6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864 * t) * t) * t) * t) * + t; + return t * (0.04213 + 0.01365 / n) / n; + } +} + +// Returns the AndersonDarling p-value given n and the value of the statistic +double AndersonDarlingPValue(int n, double z) { + double ad = AndersonDarlingInf(z); + double errfix = AndersonDarlingErrFix(n, ad); + return ad + errfix; +} + +double AndersonDarlingStatistic(const std::vector& random_sample) { + int n = random_sample.size(); + double ad_sum = 0; + for (int i = 0; i < n; i++) { + ad_sum += (2 * i + 1) * + std::log(random_sample[i] * (1 - random_sample[n - 1 - i])); + } + double ad_statistic = -n - 1 / static_cast(n) * ad_sum; + return ad_statistic; +} + +// Tests if the array of doubles is uniformly distributed. +// Returns the p-value of the Anderson Darling Statistic +// for the given set of sorted random doubles +// See "Evaluating the Anderson-Darling Distribution" by +// Marsaglia and Marsaglia for details. +double AndersonDarlingTest(const std::vector& random_sample) { + double ad_statistic = AndersonDarlingStatistic(random_sample); + double p = AndersonDarlingPValue(random_sample.size(), ad_statistic); + return p; +} + +TEST(ExponentialBiasedTest, CoinTossDemoWithGetSkipCount) { + ExponentialBiased eb; + for (int runs = 0; runs < 10; ++runs) { + for (int flips = eb.GetSkipCount(1); flips > 0; --flips) { + printf("head..."); + } + printf("tail\n"); + } + int heads = 0; + for (int i = 0; i < 10000000; i += 1 + eb.GetSkipCount(1)) { + ++heads; + } + printf("Heads = %d (%f%%)\n", heads, 100.0 * heads / 10000000); +} + +TEST(ExponentialBiasedTest, SampleDemoWithStride) { + ExponentialBiased eb; + int stride = eb.GetStride(10); + int samples = 0; + for (int i = 0; i < 10000000; ++i) { + if (--stride == 0) { + ++samples; + stride = eb.GetStride(10); + } + } + printf("Samples = %d (%f%%)\n", samples, 100.0 * samples / 10000000); +} + + +// Testing that NextRandom generates uniform random numbers. Applies the +// Anderson-Darling test for uniformity +TEST(ExponentialBiasedTest, TestNextRandom) { + for (auto n : std::vector({ + 10, // Check short-range correlation + 100, 1000, + 10000 // Make sure there's no systemic error + })) { + uint64_t x = 1; + // This assumes that the prng returns 48 bit numbers + uint64_t max_prng_value = static_cast(1) << 48; + // Initialize. + for (int i = 1; i <= 20; i++) { + x = ExponentialBiased::NextRandom(x); + } + std::vector int_random_sample(n); + // Collect samples + for (int i = 0; i < n; i++) { + int_random_sample[i] = x; + x = ExponentialBiased::NextRandom(x); + } + // First sort them... + std::sort(int_random_sample.begin(), int_random_sample.end()); + std::vector random_sample(n); + // Convert them to uniform randoms (in the range [0,1]) + for (int i = 0; i < n; i++) { + random_sample[i] = + static_cast(int_random_sample[i]) / max_prng_value; + } + // Now compute the Anderson-Darling statistic + double ad_pvalue = AndersonDarlingTest(random_sample); + EXPECT_GT(std::min(ad_pvalue, 1 - ad_pvalue), 0.0001) + << "prng is not uniform: n = " << n << " p = " << ad_pvalue; + } +} + +// The generator needs to be available as a thread_local and as a static +// variable. +TEST(ExponentialBiasedTest, InitializationModes) { + ABSL_CONST_INIT static ExponentialBiased eb_static; + EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0)); + +#ifdef ABSL_HAVE_THREAD_LOCAL + thread_local ExponentialBiased eb_thread; + EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0)); +#endif + + ExponentialBiased eb_stack; + EXPECT_THAT(eb_stack.GetSkipCount(2), Ge(0)); +} + +} // namespace profiling_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/profiling/internal/periodic_sampler.cc b/absl/profiling/internal/periodic_sampler.cc new file mode 100644 index 00000000..a738a82c --- /dev/null +++ b/absl/profiling/internal/periodic_sampler.cc @@ -0,0 +1,53 @@ +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/profiling/internal/periodic_sampler.h" + +#include + +#include "absl/profiling/internal/exponential_biased.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace profiling_internal { + +int64_t PeriodicSamplerBase::GetExponentialBiased(int period) noexcept { + return rng_.GetStride(period); +} + +bool PeriodicSamplerBase::SubtleConfirmSample() noexcept { + int current_period = period(); + + // Deal with period case 0 (always off) and 1 (always on) + if (ABSL_PREDICT_FALSE(current_period < 2)) { + stride_ = 0; + return current_period == 1; + } + + // Check if this is the first call to Sample() + if (ABSL_PREDICT_FALSE(stride_ == 1)) { + stride_ = static_cast(-GetExponentialBiased(current_period)); + if (static_cast(stride_) < -1) { + ++stride_; + return false; + } + } + + stride_ = static_cast(-GetExponentialBiased(current_period)); + return true; +} + +} // namespace profiling_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/profiling/internal/periodic_sampler.h b/absl/profiling/internal/periodic_sampler.h new file mode 100644 index 00000000..54f0af45 --- /dev/null +++ b/absl/profiling/internal/periodic_sampler.h @@ -0,0 +1,211 @@ +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_PROFILING_INTERNAL_PERIODIC_SAMPLER_H_ +#define ABSL_PROFILING_INTERNAL_PERIODIC_SAMPLER_H_ + +#include + +#include + +#include "absl/base/optimization.h" +#include "absl/profiling/internal/exponential_biased.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace profiling_internal { + +// PeriodicSamplerBase provides the basic period sampler implementation. +// +// This is the base class for the templated PeriodicSampler class, which holds +// a global std::atomic value identified by a user defined tag, such that +// each specific PeriodSampler implementation holds its own global period. +// +// PeriodicSamplerBase is thread-compatible except where stated otherwise. +class PeriodicSamplerBase { + public: + // PeriodicSamplerBase is trivial / copyable / movable / destructible. + PeriodicSamplerBase() = default; + PeriodicSamplerBase(PeriodicSamplerBase&&) = default; + PeriodicSamplerBase(const PeriodicSamplerBase&) = default; + + // Returns true roughly once every `period` calls. This is established by a + // randomly picked `stride` that is counted down on each call to `Sample`. + // This stride is picked such that the probability of `Sample()` returning + // true is 1 in `period`. + inline bool Sample() noexcept; + + // The below methods are intended for optimized use cases where the + // size of the inlined fast path code is highly important. Applications + // should use the `Sample()` method unless they have proof that their + // specific use case requires the optimizations offered by these methods. + // + // An example of such a use case is SwissTable sampling. All sampling checks + // are in inlined SwissTable methods, and the number of call sites is huge. + // In this case, the inlined code size added to each translation unit calling + // SwissTable methods is non-trivial. + // + // The `SubtleMaybeSample()` function spuriously returns true even if the + // function should not be sampled, applications MUST match each call to + // 'SubtleMaybeSample()' returning true with a `SubtleConfirmSample()` call, + // and use the result of the latter as the sampling decision. + // In other words: the code should logically be equivalent to: + // + // if (SubtleMaybeSample() && SubtleConfirmSample()) { + // // Sample this call + // } + // + // In the 'inline-size' optimized case, the `SubtleConfirmSample()` call can + // be placed out of line, for example, the typical use case looks as follows: + // + // // --- frobber.h ----------- + // void FrobberSampled(); + // + // inline void FrobberImpl() { + // // ... + // } + // + // inline void Frobber() { + // if (ABSL_PREDICT_FALSE(sampler.SubtleMaybeSample())) { + // FrobberSampled(); + // } else { + // FrobberImpl(); + // } + // } + // + // // --- frobber.cc ----------- + // void FrobberSampled() { + // if (!sampler.SubtleConfirmSample())) { + // // Spurious false positive + // FrobberImpl(); + // return; + // } + // + // // Sampled execution + // // ... + // } + inline bool SubtleMaybeSample() noexcept; + bool SubtleConfirmSample() noexcept; + + protected: + // We explicitly don't use a virtual destructor as this class is never + // virtually destroyed, and it keeps the class trivial, which avoids TLS + // prologue and epilogue code for our TLS instances. + ~PeriodicSamplerBase() = default; + + // Returns the next stride for our sampler. + // This function is virtual for testing purposes only. + virtual int64_t GetExponentialBiased(int period) noexcept; + + private: + // Returns the current period of this sampler. Thread-safe. + virtual int period() const noexcept = 0; + + // Keep and decrement stride_ as an unsigned integer, but compare the value + // to zero casted as a signed int. clang and msvc do not create optimum code + // if we use signed for the combined decrement and sign comparison. + // + // Below 3 alternative options, all compiles generate the best code + // using the unsigned increment <---> signed int comparison option. + // + // Option 1: + // int64_t stride_; + // if (ABSL_PREDICT_TRUE(++stride_ < 0)) { ... } + // + // GCC x64 (OK) : https://gcc.godbolt.org/z/R5MzzA + // GCC ppc (OK) : https://gcc.godbolt.org/z/z7NZAt + // Clang x64 (BAD): https://gcc.godbolt.org/z/t4gPsd + // ICC x64 (OK) : https://gcc.godbolt.org/z/rE6s8W + // MSVC x64 (OK) : https://gcc.godbolt.org/z/ARMXqS + // + // Option 2: + // int64_t stride_ = 0; + // if (ABSL_PREDICT_TRUE(--stride_ >= 0)) { ... } + // + // GCC x64 (OK) : https://gcc.godbolt.org/z/jSQxYK + // GCC ppc (OK) : https://gcc.godbolt.org/z/VJdYaA + // Clang x64 (BAD): https://gcc.godbolt.org/z/Xm4NjX + // ICC x64 (OK) : https://gcc.godbolt.org/z/4snaFd + // MSVC x64 (BAD): https://gcc.godbolt.org/z/BgnEKE + // + // Option 3: + // uint64_t stride_; + // if (ABSL_PREDICT_TRUE(static_cast(++stride_) < 0)) { ... } + // + // GCC x64 (OK) : https://gcc.godbolt.org/z/bFbfPy + // GCC ppc (OK) : https://gcc.godbolt.org/z/S9KkUE + // Clang x64 (OK) : https://gcc.godbolt.org/z/UYzRb4 + // ICC x64 (OK) : https://gcc.godbolt.org/z/ptTNfD + // MSVC x64 (OK) : https://gcc.godbolt.org/z/76j4-5 + uint64_t stride_ = 0; + absl::profiling_internal::ExponentialBiased rng_; +}; + +inline bool PeriodicSamplerBase::SubtleMaybeSample() noexcept { + // See comments on `stride_` for the unsigned increment / signed compare. + if (ABSL_PREDICT_TRUE(static_cast(++stride_) < 0)) { + return false; + } + return true; +} + +inline bool PeriodicSamplerBase::Sample() noexcept { + return ABSL_PREDICT_FALSE(SubtleMaybeSample()) ? SubtleConfirmSample() + : false; +} + +// PeriodicSampler is a concreted periodic sampler implementation. +// The user provided Tag identifies the implementation, and is required to +// isolate the global state of this instance from other instances. +// +// Typical use case: +// +// struct HashTablezTag {}; +// thread_local PeriodicSampler sampler; +// +// void HashTableSamplingLogic(...) { +// if (sampler.Sample()) { +// HashTableSlowSamplePath(...); +// } +// } +// +template +class PeriodicSampler final : public PeriodicSamplerBase { + public: + ~PeriodicSampler() = default; + + int period() const noexcept final { + return period_.load(std::memory_order_relaxed); + } + + // Sets the global period for this sampler. Thread-safe. + // Setting a period of 0 disables the sampler, i.e., every call to Sample() + // will return false. Setting a period of 1 puts the sampler in 'always on' + // mode, i.e., every call to Sample() returns true. + static void SetGlobalPeriod(int period) { + period_.store(period, std::memory_order_relaxed); + } + + private: + static std::atomic period_; +}; + +template +std::atomic PeriodicSampler::period_(default_period); + +} // namespace profiling_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_PROFILING_INTERNAL_PERIODIC_SAMPLER_H_ diff --git a/absl/profiling/internal/periodic_sampler_benchmark.cc b/absl/profiling/internal/periodic_sampler_benchmark.cc new file mode 100644 index 00000000..8f0e5574 --- /dev/null +++ b/absl/profiling/internal/periodic_sampler_benchmark.cc @@ -0,0 +1,79 @@ +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/profiling/internal/periodic_sampler.h" +#include "benchmark/benchmark.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace profiling_internal { +namespace { + +template +void BM_Sample(Sampler* sampler, benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize(sampler); + benchmark::DoNotOptimize(sampler->Sample()); + } +} + +template +void BM_SampleMinunumInlined(Sampler* sampler, benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize(sampler); + if (ABSL_PREDICT_FALSE(sampler->SubtleMaybeSample())) { + benchmark::DoNotOptimize(sampler->SubtleConfirmSample()); + } + } +} + +void BM_PeriodicSampler_TinySample(benchmark::State& state) { + struct Tag {}; + PeriodicSampler sampler; + BM_Sample(&sampler, state); +} +BENCHMARK(BM_PeriodicSampler_TinySample); + +void BM_PeriodicSampler_ShortSample(benchmark::State& state) { + struct Tag {}; + PeriodicSampler sampler; + BM_Sample(&sampler, state); +} +BENCHMARK(BM_PeriodicSampler_ShortSample); + +void BM_PeriodicSampler_LongSample(benchmark::State& state) { + struct Tag {}; + PeriodicSampler sampler; + BM_Sample(&sampler, state); +} +BENCHMARK(BM_PeriodicSampler_LongSample); + +void BM_PeriodicSampler_LongSampleMinunumInlined(benchmark::State& state) { + struct Tag {}; + PeriodicSampler sampler; + BM_SampleMinunumInlined(&sampler, state); +} +BENCHMARK(BM_PeriodicSampler_LongSampleMinunumInlined); + +void BM_PeriodicSampler_Disabled(benchmark::State& state) { + struct Tag {}; + PeriodicSampler sampler; + BM_Sample(&sampler, state); +} +BENCHMARK(BM_PeriodicSampler_Disabled); + +} // namespace +} // namespace profiling_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/profiling/internal/periodic_sampler_test.cc b/absl/profiling/internal/periodic_sampler_test.cc new file mode 100644 index 00000000..ef986f38 --- /dev/null +++ b/absl/profiling/internal/periodic_sampler_test.cc @@ -0,0 +1,177 @@ +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/profiling/internal/periodic_sampler.h" + +#include // NOLINT(build/c++11) + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/attributes.h" +#include "absl/base/macros.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace profiling_internal { +namespace { + +using testing::Eq; +using testing::Return; +using testing::StrictMock; + +class MockPeriodicSampler : public PeriodicSamplerBase { + public: + virtual ~MockPeriodicSampler() = default; + + MOCK_METHOD(int, period, (), (const, noexcept)); + MOCK_METHOD(int64_t, GetExponentialBiased, (int), (noexcept)); +}; + +TEST(PeriodicSamplerBaseTest, Sample) { + StrictMock sampler; + + EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(16)); + EXPECT_CALL(sampler, GetExponentialBiased(16)) + .WillOnce(Return(2)) + .WillOnce(Return(3)) + .WillOnce(Return(4)); + + EXPECT_FALSE(sampler.Sample()); + EXPECT_TRUE(sampler.Sample()); + + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); + EXPECT_TRUE(sampler.Sample()); + + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); +} + +TEST(PeriodicSamplerBaseTest, ImmediatelySample) { + StrictMock sampler; + + EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16)); + EXPECT_CALL(sampler, GetExponentialBiased(16)) + .WillOnce(Return(1)) + .WillOnce(Return(2)) + .WillOnce(Return(3)); + + EXPECT_TRUE(sampler.Sample()); + + EXPECT_FALSE(sampler.Sample()); + EXPECT_TRUE(sampler.Sample()); + + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); +} + +TEST(PeriodicSamplerBaseTest, Disabled) { + StrictMock sampler; + + EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(0)); + + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); +} + +TEST(PeriodicSamplerBaseTest, AlwaysOn) { + StrictMock sampler; + + EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(1)); + + EXPECT_TRUE(sampler.Sample()); + EXPECT_TRUE(sampler.Sample()); + EXPECT_TRUE(sampler.Sample()); +} + +TEST(PeriodicSamplerBaseTest, Disable) { + StrictMock sampler; + + EXPECT_CALL(sampler, period()).WillOnce(Return(16)); + EXPECT_CALL(sampler, GetExponentialBiased(16)).WillOnce(Return(3)); + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); + + EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(0)); + + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); +} + +TEST(PeriodicSamplerBaseTest, Enable) { + StrictMock sampler; + + EXPECT_CALL(sampler, period()).WillOnce(Return(0)); + EXPECT_FALSE(sampler.Sample()); + + EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16)); + EXPECT_CALL(sampler, GetExponentialBiased(16)) + .Times(2) + .WillRepeatedly(Return(3)); + + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); + EXPECT_TRUE(sampler.Sample()); + + EXPECT_FALSE(sampler.Sample()); + EXPECT_FALSE(sampler.Sample()); +} + +TEST(PeriodicSamplerTest, ConstructConstInit) { + struct Tag {}; + ABSL_CONST_INIT static PeriodicSampler sampler; + (void)sampler; +} + +TEST(PeriodicSamplerTest, DefaultPeriod0) { + struct Tag {}; + PeriodicSampler sampler; + EXPECT_THAT(sampler.period(), Eq(0)); +} + +TEST(PeriodicSamplerTest, DefaultPeriod) { + struct Tag {}; + PeriodicSampler sampler; + EXPECT_THAT(sampler.period(), Eq(100)); +} + +TEST(PeriodicSamplerTest, SetGlobalPeriod) { + struct Tag1 {}; + struct Tag2 {}; + PeriodicSampler sampler1; + PeriodicSampler sampler2; + + EXPECT_THAT(sampler1.period(), Eq(25)); + EXPECT_THAT(sampler2.period(), Eq(50)); + + std::thread thread([] { + PeriodicSampler sampler1; + PeriodicSampler sampler2; + EXPECT_THAT(sampler1.period(), Eq(25)); + EXPECT_THAT(sampler2.period(), Eq(50)); + sampler1.SetGlobalPeriod(10); + sampler2.SetGlobalPeriod(20); + }); + thread.join(); + + EXPECT_THAT(sampler1.period(), Eq(10)); + EXPECT_THAT(sampler2.period(), Eq(20)); +} + +} // namespace +} // namespace profiling_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/status/status.h b/absl/status/status.h index 638b9ca4..9bb45382 100644 --- a/absl/status/status.h +++ b/absl/status/status.h @@ -494,7 +494,7 @@ class Status final { // Returns the error message associated with this error code, if available. // Note that this message rarely describes the error code. It is not unusual // for the error message to be the empty string. As a result, prefer - // `Status::ToString()` for debug logging. + // `operator<<` or `Status::ToString()` for debug logging. absl::string_view message() const; friend bool operator==(const Status&, const Status&); diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index f9735b4b..c45a671e 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -508,8 +508,8 @@ cc_library( deps = [ "//absl/base:config", "//absl/base:core_headers", - "//absl/base:exponential_biased", "//absl/base:raw_logging_internal", + "//absl/profiling:exponential_biased", ], ) diff --git a/absl/strings/internal/cordz_functions.cc b/absl/strings/internal/cordz_functions.cc index 48369933..20d314f0 100644 --- a/absl/strings/internal/cordz_functions.cc +++ b/absl/strings/internal/cordz_functions.cc @@ -21,8 +21,8 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" -#include "absl/base/internal/exponential_biased.h" #include "absl/base/internal/raw_logging.h" +#include "absl/profiling/internal/exponential_biased.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -48,7 +48,7 @@ constexpr int64_t kIntervalIfDisabled = 1 << 16; ABSL_ATTRIBUTE_NOINLINE bool cordz_should_profile_slow() { - thread_local absl::base_internal::ExponentialBiased + thread_local absl::profiling_internal::ExponentialBiased exponential_biased_generator; int32_t mean_interval = get_cordz_mean_interval(); diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc index f8fbf948..4f403176 100644 --- a/absl/synchronization/mutex_test.cc +++ b/absl/synchronization/mutex_test.cc @@ -26,6 +26,7 @@ #include #include #include // NOLINT(build/c++11) +#include #include #include "gtest/gtest.h" @@ -870,33 +871,6 @@ TEST(Mutex, LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS { } } -// -------------------------------------------------------- -// Test for bug with pattern of readers using a condvar. The bug was that if a -// reader went to sleep on a condition variable while one or more other readers -// held the lock, but there were no waiters, the reader count (held in the -// mutex word) would be lost. (This is because Enqueue() had at one time -// always placed the thread on the Mutex queue. Later (CL 4075610), to -// tolerate re-entry into Mutex from a Condition predicate, Enqueue() was -// changed so that it could also place a thread on a condition-variable. This -// introduced the case where Enqueue() returned with an empty queue, and this -// case was handled incorrectly in one place.) - -static void ReaderForReaderOnCondVar(absl::Mutex *mu, absl::CondVar *cv, - int *running) { - std::random_device dev; - std::mt19937 gen(dev()); - std::uniform_int_distribution random_millis(0, 15); - mu->ReaderLock(); - while (*running == 3) { - absl::SleepFor(absl::Milliseconds(random_millis(gen))); - cv->WaitWithTimeout(mu, absl::Milliseconds(random_millis(gen))); - } - mu->ReaderUnlock(); - mu->Lock(); - (*running)--; - mu->Unlock(); -} - struct True { template bool operator()(Args...) const { @@ -945,6 +919,33 @@ TEST(Mutex, FunctorCondition) { } } +// -------------------------------------------------------- +// Test for bug with pattern of readers using a condvar. The bug was that if a +// reader went to sleep on a condition variable while one or more other readers +// held the lock, but there were no waiters, the reader count (held in the +// mutex word) would be lost. (This is because Enqueue() had at one time +// always placed the thread on the Mutex queue. Later (CL 4075610), to +// tolerate re-entry into Mutex from a Condition predicate, Enqueue() was +// changed so that it could also place a thread on a condition-variable. This +// introduced the case where Enqueue() returned with an empty queue, and this +// case was handled incorrectly in one place.) + +static void ReaderForReaderOnCondVar(absl::Mutex *mu, absl::CondVar *cv, + int *running) { + std::random_device dev; + std::mt19937 gen(dev()); + std::uniform_int_distribution random_millis(0, 15); + mu->ReaderLock(); + while (*running == 3) { + absl::SleepFor(absl::Milliseconds(random_millis(gen))); + cv->WaitWithTimeout(mu, absl::Milliseconds(random_millis(gen))); + } + mu->ReaderUnlock(); + mu->Lock(); + (*running)--; + mu->Unlock(); +} + static bool IntIsZero(int *x) { return *x == 0; } // Test for reader waiting condition variable when there are other readers diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc index 4e39188f..6770ad6b 100644 --- a/absl/time/internal/cctz/src/cctz_benchmark.cc +++ b/absl/time/internal/cctz/src/cctz_benchmark.cc @@ -648,6 +648,7 @@ const char* const kTimeZoneNames[] = {"Africa/Abidjan", "Pacific/Guam", "Pacific/Honolulu", "Pacific/Johnston", + "Pacific/Kanton", "Pacific/Kiritimati", "Pacific/Kosrae", "Pacific/Kwajalein", diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index 6948c3ea..8751b346 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -579,6 +579,7 @@ const char* const kTimeZoneNames[] = {"Africa/Abidjan", "Pacific/Guam", "Pacific/Honolulu", "Pacific/Johnston", + "Pacific/Kanton", "Pacific/Kiritimati", "Pacific/Kosrae", "Pacific/Kwajalein", diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version index ba5601ef..51191b57 100644 --- a/absl/time/internal/cctz/testdata/version +++ b/absl/time/internal/cctz/testdata/version @@ -1 +1 @@ -2021b +2021c diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen index 465546bd..dfc50957 100644 Binary files a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen and b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen differ -- cgit v1.2.3 From 59672bec983cb49050363cb47c261a450603409a Mon Sep 17 00:00:00 2001 From: Yesudeep Mangalapilly Date: Fri, 8 Oct 2021 07:50:33 -0700 Subject: Use FreeBSD macro definition for ElfW macro for compatibility. (#1037) --- absl/debugging/internal/elf_mem_image.h | 4 ++++ absl/debugging/internal/vdso_support.cc | 5 +++++ absl/debugging/symbolize_elf.inc | 4 ++++ 3 files changed, 13 insertions(+) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index 86474819..a894bd42 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -40,6 +40,10 @@ #include // for ElfW +#if defined(__FreeBSD__) && !defined(ElfW) +#define ElfW(x) __ElfN(x) +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc index 0dfe9ca6..977a9f6b 100644 --- a/absl/debugging/internal/vdso_support.cc +++ b/absl/debugging/internal/vdso_support.cc @@ -50,6 +50,11 @@ #define AT_SYSINFO_EHDR 33 // for crosstoolv10 #endif +#if defined(__FreeBSD__) +using Elf64_auxv_t = Elf64_Auxinfo; +using Elf32_auxv_t = Elf32_Auxinfo; +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index 87dbd078..3ff343d6 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc @@ -77,6 +77,10 @@ #include "absl/debugging/internal/vdso_support.h" #include "absl/strings/string_view.h" +#if defined(__FreeBSD__) && !defined(ElfW) +#define ElfW(x) __ElfN(x) +#endif + namespace absl { ABSL_NAMESPACE_BEGIN -- cgit v1.2.3 From 22f482f0fc25825dd3783f2e8642a8226b7293d4 Mon Sep 17 00:00:00 2001 From: Vertexwahn Date: Thu, 14 Oct 2021 19:01:52 +0200 Subject: Remove bazelbuild/rules_cc dependency (#1038) --- WORKSPACE | 8 -------- absl/algorithm/BUILD.bazel | 1 - absl/base/BUILD.bazel | 1 - absl/cleanup/BUILD.bazel | 1 - absl/container/BUILD.bazel | 1 - absl/debugging/BUILD.bazel | 1 - absl/flags/BUILD.bazel | 1 - absl/functional/BUILD.bazel | 1 - absl/hash/BUILD.bazel | 1 - absl/memory/BUILD.bazel | 1 - absl/meta/BUILD.bazel | 1 - absl/numeric/BUILD.bazel | 1 - absl/random/BUILD.bazel | 1 - absl/random/internal/BUILD.bazel | 2 -- absl/status/BUILD.bazel | 1 - absl/strings/BUILD.bazel | 1 - absl/synchronization/BUILD.bazel | 1 - absl/time/BUILD.bazel | 1 - absl/time/internal/cctz/BUILD.bazel | 2 -- absl/types/BUILD.bazel | 1 - absl/utility/BUILD.bazel | 1 - 21 files changed, 30 deletions(-) (limited to 'absl/debugging') diff --git a/WORKSPACE b/WORKSPACE index 84ab3ed4..c9aa8caf 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -35,14 +35,6 @@ http_archive( urls = ["https://github.com/google/benchmark/archive/0baacde3618ca617da95375e0af13ce1baadea47.zip"], ) -# C++ rules for Bazel. -http_archive( - name = "rules_cc", # 2021-06-07T16:41:49Z - sha256 = "b295cad8c5899e371dde175079c0a2cdc0151f5127acc92366a8c986beb95c76", - strip_prefix = "rules_cc-daf6ace7cfeacd6a83e9ff2ed659f416537b6c74", - urls = ["https://github.com/bazelbuild/rules_cc/archive/daf6ace7cfeacd6a83e9ff2ed659f416537b6c74.zip"], -) - # Bazel platform rules. http_archive( name = "platforms", diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel index a3002b7d..afc52639 100644 --- a/absl/algorithm/BUILD.bazel +++ b/absl/algorithm/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 8b09b6e3..4769efda 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/cleanup/BUILD.bazel b/absl/cleanup/BUILD.bazel index 5cca898f..2154d9f1 100644 --- a/absl/cleanup/BUILD.bazel +++ b/absl/cleanup/BUILD.bazel @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index 9e3bc06a..d1df524a 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index b503da51..3c4ea8dc 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 7957c6dd..d20deab4 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel index 4555cd59..f9f2b9c2 100644 --- a/absl/functional/BUILD.bazel +++ b/absl/functional/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index 392b68f1..f0640d34 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel index d2824a05..c16bf8a9 100644 --- a/absl/memory/BUILD.bazel +++ b/absl/memory/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel index 5585fcca..fb379251 100644 --- a/absl/meta/BUILD.bazel +++ b/absl/meta/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel index ea587bfa..1f9e0f20 100644 --- a/absl/numeric/BUILD.bazel +++ b/absl/numeric/BUILD.bazel @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel index 66ffcbc7..fdde78b6 100644 --- a/absl/random/BUILD.bazel +++ b/absl/random/BUILD.bazel @@ -16,7 +16,6 @@ # ABSL random-number generation libraries. -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel index df6e42fc..e93eebb6 100644 --- a/absl/random/internal/BUILD.bazel +++ b/absl/random/internal/BUILD.bazel @@ -14,8 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") - # Internal-only implementation classes for Abseil Random load( "//absl:copts/configure_copts.bzl", diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel index 30df22ae..0e5b3508 100644 --- a/absl/status/BUILD.bazel +++ b/absl/status/BUILD.bazel @@ -17,7 +17,6 @@ # It will expand later to have utilities around `Status` like `StatusOr`, # `StatusBuilder` and macros. -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index c45a671e..c046366c 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index 92e2448d..d7195473 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel index 3e25ca26..e8c49660 100644 --- a/absl/time/BUILD.bazel +++ b/absl/time/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel index f549af66..bdc2e309 100644 --- a/absl/time/internal/cctz/BUILD.bazel +++ b/absl/time/internal/cctz/BUILD.bazel @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") - package(features = ["-parse_headers"]) licenses(["notice"]) diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index 83be9360..38ed2286 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel index 02b2c407..ca4bc0a6 100644 --- a/absl/utility/BUILD.bazel +++ b/absl/utility/BUILD.bazel @@ -14,7 +14,6 @@ # limitations under the License. # -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", -- cgit v1.2.3 From a2f52e1177b87bdc747f8d0b7745c8f967bceb9d Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 18 Oct 2021 08:24:39 -0700 Subject: Export of internal Abseil changes -- b008f3aaab60f1f0eb5987b50336543cca7151be by Martijn Vels : Enable Cord Btree as the default Cord implementation. The Cord Btree implementation has been extensively tested by google. This changes makes the Cord Btree implementation the default implementation. This change should have no impact on current use cases and does not effect any public API or behavior. PiperOrigin-RevId: 403966449 -- 3d82052b5819d1244942c59d5cb4e51d75ada287 by Derek Mauro : Add missing CMake alias for gmock_main. Remove unused variable ABSL_TEST_COMMON_LIBRARIES Fixes #709 Fixes #1043 PiperOrigin-RevId: 403950358 -- 86695f6d06915b56d807303c37ee81487998cd58 by Abseil Team : FunctionRef is cheaper to construct than a std::function, and the argument is only used during the call, so this is safe. This has the added advantage of allowing the caller to provide a non-movable callable, which can't be converted to a std::function. PiperOrigin-RevId: 403457615 -- 196c1109ba519d4ff00c856bbb4bff754468359f by Abseil Team : Internal optimization. PiperOrigin-RevId: 403413291 GitOrigin-RevId: b008f3aaab60f1f0eb5987b50336543cca7151be Change-Id: I1665f0efd484f53e0ed22d8940ef2fa60b03cc5b --- CMakeLists.txt | 10 ++-------- absl/debugging/internal/stacktrace_x86-inl.inc | 25 ++++++++++++++++++++++--- absl/status/BUILD.bazel | 1 + absl/status/CMakeLists.txt | 1 + absl/status/status.cc | 2 +- absl/status/status.h | 3 ++- absl/strings/internal/cord_internal.h | 2 +- 7 files changed, 30 insertions(+), 14 deletions(-) (limited to 'absl/debugging') diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c8bfff4..d59c2ade 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,22 +160,16 @@ if(BUILD_TESTING) if (NOT ABSL_FIND_GOOGLETEST) # When Google Test is included directly rather than through find_package, the aliases are missing. - add_library(GTest::gtest_main ALIAS gtest_main) add_library(GTest::gtest ALIAS gtest) + add_library(GTest::gtest_main ALIAS gtest_main) add_library(GTest::gmock ALIAS gmock) + add_library(GTest::gmock_main ALIAS gmock_main) endif() check_target(GTest::gtest) check_target(GTest::gtest_main) check_target(GTest::gmock) check_target(GTest::gmock_main) - - list(APPEND ABSL_TEST_COMMON_LIBRARIES - GTest::gtest_main - GTest::gtest - GTest::gmock - ${CMAKE_THREAD_LIBS_INIT} - ) endif() add_subdirectory(absl) diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc index 70f79dfc..847a5473 100644 --- a/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/absl/debugging/internal/stacktrace_x86-inl.inc @@ -27,6 +27,7 @@ #include #include +#include #include "absl/base/macros.h" #include "absl/base/port.h" @@ -158,7 +159,8 @@ static uintptr_t GetFP(const void *vuc) { template ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. -static void **NextStackFrame(void **old_fp, const void *uc) { +static void **NextStackFrame(void **old_fp, const void *uc, + size_t stack_low, size_t stack_high) { void **new_fp = (void **)*old_fp; #if defined(__linux__) && defined(__i386__) @@ -257,6 +259,18 @@ static void **NextStackFrame(void **old_fp, const void *uc) { // at a greater address that the current one. if (new_fp_u <= old_fp_u) return nullptr; if (new_fp_u - old_fp_u > kMaxFrameBytes) return nullptr; + + if (stack_low < old_fp_u && old_fp_u <= stack_high) { + // Old BP was in the expected stack region... + if (!(stack_low < new_fp_u && new_fp_u <= stack_high)) { + // ... but new BP is outside of expected stack region. + // It is most likely bogus. + return nullptr; + } + } else { + // We may be here if we are executing in a co-routine with a + // separate stack. We can't do safety checks in this case. + } } else { if (new_fp == nullptr) return nullptr; // skip AddressIsReadable() below // In the non-strict mode, allow discontiguous stack frames. @@ -296,13 +310,17 @@ static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, int n = 0; void **fp = reinterpret_cast(__builtin_frame_address(0)); + size_t stack_low = getpagesize(); // Assume that the first page is not stack. + size_t stack_high = std::numeric_limits::max() - sizeof(void *); + while (fp && n < max_depth) { if (*(fp + 1) == reinterpret_cast(0)) { // In 64-bit code, we often see a frame that // points to itself and has a return address of 0. break; } - void **next_fp = NextStackFrame(fp, ucp); + void **next_fp = NextStackFrame( + fp, ucp, stack_low, stack_high); if (skip_count > 0) { skip_count--; } else { @@ -325,7 +343,8 @@ static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, const int kMaxUnwind = 1000; int j = 0; for (; fp != nullptr && j < kMaxUnwind; j++) { - fp = NextStackFrame(fp, ucp); + fp = NextStackFrame(fp, ucp, stack_low, + stack_high); } *min_dropped_frames = j; } diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel index 0e5b3508..bae5156f 100644 --- a/absl/status/BUILD.bazel +++ b/absl/status/BUILD.bazel @@ -47,6 +47,7 @@ cc_library( "//absl/container:inlined_vector", "//absl/debugging:stacktrace", "//absl/debugging:symbolize", + "//absl/functional:function_ref", "//absl/strings", "//absl/strings:cord", "//absl/strings:str_format", diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt index 43898564..f107c85b 100644 --- a/absl/status/CMakeLists.txt +++ b/absl/status/CMakeLists.txt @@ -29,6 +29,7 @@ absl_cc_library( absl::atomic_hook absl::config absl::core_headers + absl::function_ref absl::raw_logging_internal absl::inlined_vector absl::stacktrace diff --git a/absl/status/status.cc b/absl/status/status.cc index 53c198e1..bcf3413e 100644 --- a/absl/status/status.cc +++ b/absl/status/status.cc @@ -161,7 +161,7 @@ bool Status::ErasePayload(absl::string_view type_url) { } void Status::ForEachPayload( - const std::function& visitor) + absl::FunctionRef visitor) const { if (auto* payloads = GetPayloads()) { bool in_reverse = diff --git a/absl/status/status.h b/absl/status/status.h index 9bb45382..39071e5f 100644 --- a/absl/status/status.h +++ b/absl/status/status.h @@ -55,6 +55,7 @@ #include #include "absl/container/inlined_vector.h" +#include "absl/functional/function_ref.h" #include "absl/status/internal/status_internal.h" #include "absl/strings/cord.h" #include "absl/strings/string_view.h" @@ -590,7 +591,7 @@ class Status final { // NOTE: Any mutation on the same 'absl::Status' object during visitation is // forbidden and could result in undefined behavior. void ForEachPayload( - const std::function& visitor) + absl::FunctionRef visitor) const; private: diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h index 7172b147..0300ac40 100644 --- a/absl/strings/internal/cord_internal.h +++ b/absl/strings/internal/cord_internal.h @@ -37,7 +37,7 @@ class CordzInfo; // Default feature enable states for cord ring buffers enum CordFeatureDefaults { - kCordEnableBtreeDefault = false, + kCordEnableBtreeDefault = true, kCordEnableRingBufferDefault = false, kCordShallowSubcordsDefault = false }; -- cgit v1.2.3 From d6c75d9dd895922bf5dc6c38245ac8887d3e68fc Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 3 Nov 2021 08:46:25 -0700 Subject: Export of internal Abseil changes -- 9f6ef337f282272bc098330c9ccacd9d39155db4 by Abseil Team : Make DestroyElements an empty function if the value types are trivially deconstructible. PiperOrigin-RevId: 407345743 -- a639bbf6f22446d6ba3da9e2c205e26cda4bebc5 by Derek Mauro : Add ctest --output-on-failure to the CMake install test PiperOrigin-RevId: 407333671 -- 54d0577fa6ba1159c6a86410ae185c52f4afaff6 by Derek Mauro : Fix Android build of elf_mem_image.cc PiperOrigin-RevId: 407331032 GitOrigin-RevId: 9f6ef337f282272bc098330c9ccacd9d39155db4 Change-Id: I7e13f01cd804aec50f280ac25934c9ec48ef3c5f --- CMake/install_test_project/test.sh | 2 +- absl/container/inlined_vector.h | 12 +++--- absl/container/internal/inlined_vector.h | 65 +++++++++++++++++++++----------- absl/debugging/internal/elf_mem_image.cc | 2 +- 4 files changed, 51 insertions(+), 30 deletions(-) (limited to 'absl/debugging') diff --git a/CMake/install_test_project/test.sh b/CMake/install_test_project/test.sh index 5a78c92c..aecbb8fe 100755 --- a/CMake/install_test_project/test.sh +++ b/CMake/install_test_project/test.sh @@ -58,7 +58,7 @@ cmake "${absl_dir}" \ -DBUILD_TESTING=ON \ -DBUILD_SHARED_LIBS="${build_shared_libs}" make -j $(nproc) -ctest -j $(nproc) +ctest -j $(nproc) --output-on-failure make install ldconfig popd diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h index df9e0991..318c4679 100644 --- a/absl/container/inlined_vector.h +++ b/absl/container/inlined_vector.h @@ -233,8 +233,8 @@ class InlinedVector { // specified allocator is also `noexcept`. InlinedVector( InlinedVector&& other, - const allocator_type& allocator) - noexcept(absl::allocator_is_nothrow::value) + const allocator_type& + allocator) noexcept(absl::allocator_is_nothrow::value) : storage_(allocator) { if (IsMemcpyOk::value) { storage_.MemcpyFrom(other.storage_); @@ -486,8 +486,8 @@ class InlinedVector { InlinedVector& operator=(InlinedVector&& other) { if (ABSL_PREDICT_TRUE(this != std::addressof(other))) { if (IsMemcpyOk::value || other.storage_.GetIsAllocated()) { - inlined_vector_internal::DestroyElements(storage_.GetAllocator(), - data(), size()); + inlined_vector_internal::DestroyAdapter::DestroyElements( + storage_.GetAllocator(), data(), size()); storage_.DeallocateIfAllocated(); storage_.MemcpyFrom(other.storage_); @@ -721,8 +721,8 @@ class InlinedVector { // Destroys all elements in the inlined vector, setting the size to `0` and // deallocating any held memory. void clear() noexcept { - inlined_vector_internal::DestroyElements(storage_.GetAllocator(), data(), - size()); + inlined_vector_internal::DestroyAdapter::DestroyElements( + storage_.GetAllocator(), data(), size()); storage_.DeallocateIfAllocated(); storage_.SetInlinedSize(0); diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index 1d7d6cda..26caa49a 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h @@ -94,16 +94,30 @@ struct TypeIdentity { template using NoTypeDeduction = typename TypeIdentity::type; +template >::value> +struct DestroyAdapter; + template -void DestroyElements(NoTypeDeduction& allocator, Pointer destroy_first, - SizeType destroy_size) { - if (destroy_first != nullptr) { +struct DestroyAdapter { + static void DestroyElements(A& allocator, Pointer destroy_first, + SizeType destroy_size) { for (SizeType i = destroy_size; i != 0;) { --i; AllocatorTraits::destroy(allocator, destroy_first + i); } } -} +}; + +template +struct DestroyAdapter { + static void DestroyElements(A& allocator, Pointer destroy_first, + SizeType destroy_size) { + static_cast(allocator); + static_cast(destroy_first); + static_cast(destroy_size); + } +}; template struct Allocation { @@ -133,7 +147,7 @@ void ConstructElements(NoTypeDeduction& allocator, for (SizeType i = 0; i < construct_size; ++i) { ABSL_INTERNAL_TRY { values.ConstructNext(allocator, construct_first + i); } ABSL_INTERNAL_CATCH_ANY { - DestroyElements(allocator, construct_first, i); + DestroyAdapter::DestroyElements(allocator, construct_first, i); ABSL_INTERNAL_RETHROW; } } @@ -253,7 +267,7 @@ class ConstructionTransaction { ~ConstructionTransaction() { if (DidConstruct()) { - DestroyElements(GetAllocator(), GetData(), GetSize()); + DestroyAdapter::DestroyElements(GetAllocator(), GetData(), GetSize()); } } @@ -469,7 +483,7 @@ class Storage { template void Storage::DestroyContents() { Pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData(); - DestroyElements(GetAllocator(), data, GetSize()); + DestroyAdapter::DestroyElements(GetAllocator(), data, GetSize()); DeallocateIfAllocated(); } @@ -566,7 +580,8 @@ auto Storage::Assign(ValueAdapter values, SizeType new_size) ConstructElements(GetAllocator(), construct_loop.data(), values, construct_loop.size()); - DestroyElements(GetAllocator(), destroy_loop.data(), destroy_loop.size()); + DestroyAdapter::DestroyElements(GetAllocator(), destroy_loop.data(), + destroy_loop.size()); if (allocation_tx.DidAllocate()) { DeallocateIfAllocated(); @@ -587,7 +602,7 @@ auto Storage::Resize(ValueAdapter values, SizeType new_size) A& alloc = GetAllocator(); if (new_size <= size) { // Destroy extra old elements. - DestroyElements(alloc, base + new_size, size - new_size); + DestroyAdapter::DestroyElements(alloc, base + new_size, size - new_size); } else if (new_size <= storage_view.capacity) { // Construct new elements in place. ConstructElements(alloc, base + size, values, new_size - size); @@ -611,7 +626,7 @@ auto Storage::Resize(ValueAdapter values, SizeType new_size) (MoveIterator(base))); ConstructElements(alloc, new_data, move_values, size); - DestroyElements(alloc, base, size); + DestroyAdapter::DestroyElements(alloc, base, size); std::move(construction_tx).Commit(); DeallocateIfAllocated(); SetAllocation(std::move(allocation_tx).Release()); @@ -650,7 +665,8 @@ auto Storage::Insert(ConstIterator pos, ValueAdapter values, ConstructElements(GetAllocator(), new_data + insert_end_index, move_values, storage_view.size - insert_index); - DestroyElements(GetAllocator(), storage_view.data, storage_view.size); + DestroyAdapter::DestroyElements(GetAllocator(), storage_view.data, + storage_view.size); std::move(construction_tx).Commit(); std::move(move_construction_tx).Commit(); @@ -753,7 +769,8 @@ auto Storage::EmplaceBackSlow(Args&&... args) -> Reference { ABSL_INTERNAL_RETHROW; } // Destroy elements in old backing store. - DestroyElements(GetAllocator(), storage_view.data, storage_view.size); + DestroyAdapter::DestroyElements(GetAllocator(), storage_view.data, + storage_view.size); DeallocateIfAllocated(); SetAllocation(std::move(allocation_tx).Release()); @@ -778,9 +795,9 @@ auto Storage::Erase(ConstIterator from, ConstIterator to) AssignElements(storage_view.data + erase_index, move_values, storage_view.size - erase_end_index); - DestroyElements(GetAllocator(), - storage_view.data + (storage_view.size - erase_size), - erase_size); + DestroyAdapter::DestroyElements( + GetAllocator(), storage_view.data + (storage_view.size - erase_size), + erase_size); SubtractSize(erase_size); return Iterator(storage_view.data + erase_index); @@ -804,7 +821,8 @@ auto Storage::Reserve(SizeType requested_capacity) -> void { ConstructElements(GetAllocator(), new_data, move_values, storage_view.size); - DestroyElements(GetAllocator(), storage_view.data, storage_view.size); + DestroyAdapter::DestroyElements(GetAllocator(), storage_view.data, + storage_view.size); DeallocateIfAllocated(); SetAllocation(std::move(allocation_tx).Release()); @@ -847,7 +865,8 @@ auto Storage::ShrinkToFit() -> void { ABSL_INTERNAL_RETHROW; } - DestroyElements(GetAllocator(), storage_view.data, storage_view.size); + DestroyAdapter::DestroyElements(GetAllocator(), storage_view.data, + storage_view.size); MallocAdapter::Deallocate(GetAllocator(), storage_view.data, storage_view.capacity); @@ -883,9 +902,10 @@ auto Storage::Swap(Storage* other_storage_ptr) -> void { move_values, large_ptr->GetSize() - small_ptr->GetSize()); - DestroyElements(large_ptr->GetAllocator(), - large_ptr->GetInlinedData() + small_ptr->GetSize(), - large_ptr->GetSize() - small_ptr->GetSize()); + DestroyAdapter::DestroyElements( + large_ptr->GetAllocator(), + large_ptr->GetInlinedData() + small_ptr->GetSize(), + large_ptr->GetSize() - small_ptr->GetSize()); } else { Storage* allocated_ptr = this; Storage* inlined_ptr = other_storage_ptr; @@ -909,8 +929,9 @@ auto Storage::Swap(Storage* other_storage_ptr) -> void { ABSL_INTERNAL_RETHROW; } - DestroyElements(inlined_ptr->GetAllocator(), - inlined_ptr->GetInlinedData(), inlined_ptr->GetSize()); + DestroyAdapter::DestroyElements(inlined_ptr->GetAllocator(), + inlined_ptr->GetInlinedData(), + inlined_ptr->GetSize()); inlined_ptr->SetAllocation( {allocated_storage_view.data, allocated_storage_view.capacity}); diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc index d6832eaf..29a28181 100644 --- a/absl/debugging/internal/elf_mem_image.cc +++ b/absl/debugging/internal/elf_mem_image.cc @@ -222,7 +222,7 @@ void ElfMemImage::Init(const void *base) { reinterpret_cast(dynamic_program_header->p_vaddr + relocation); for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) { - const ElfW(Xword) value = dynamic_entry->d_un.d_val + relocation; + const auto value = dynamic_entry->d_un.d_val + relocation; switch (dynamic_entry->d_tag) { case DT_HASH: hash_ = reinterpret_cast(value); -- cgit v1.2.3 From f2dbd918d8d08529800eb72f23bd2829f92104a4 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 10 Nov 2021 13:26:07 -0800 Subject: Export of internal Abseil changes -- 317c7bd0caa12fa0a4dc65dc9c8e645211f85872 by Abseil Team : Elide the Emscripten JS-based stack trace and symbolization functions when building in Standalone Mode. Users will need to set `-DSTANDALONE_WASM=1` in some toolchain(s). PiperOrigin-RevId: 408961649 -- 92ba3ab1ef3edee4b7fb9e151f2061661e7beb0a by Derek Mauro : Suppress MSVC warning "C4127: conditional expression is constant" Fixes #1004 PiperOrigin-RevId: 408920356 GitOrigin-RevId: 317c7bd0caa12fa0a4dc65dc9c8e645211f85872 Change-Id: Ieca0a9e263874ba5bd93110dc437c56bc59ad5a7 --- absl/debugging/internal/stacktrace_config.h | 3 ++- absl/debugging/symbolize.cc | 7 ++++++- absl/strings/numbers.h | 30 +++++++++++++++++------------ 3 files changed, 26 insertions(+), 14 deletions(-) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h index ff21b719..3929b1b7 100644 --- a/absl/debugging/internal/stacktrace_config.h +++ b/absl/debugging/internal/stacktrace_config.h @@ -37,7 +37,8 @@ "absl/debugging/internal/stacktrace_generic-inl.inc" #endif // defined(ABSL_HAVE_THREAD_LOCAL) -#elif defined(__EMSCRIPTEN__) +// Emscripten stacktraces rely on JS. Do not use them in standalone mode. +#elif defined(__EMSCRIPTEN__) && !defined(STANDALONE_WASM) #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_emscripten-inl.inc" diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc index f1abdfda..638d3954 100644 --- a/absl/debugging/symbolize.cc +++ b/absl/debugging/symbolize.cc @@ -23,6 +23,11 @@ #endif #endif +// Emscripten symbolization relies on JS. Do not use them in standalone mode. +#if defined(__EMSCRIPTEN__) && !defined(STANDALONE_WASM) +#define ABSL_INTERNAL_HAVE_SYMBOLIZE_WASM +#endif + #if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) #include "absl/debugging/symbolize_elf.inc" #elif defined(ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32) @@ -31,7 +36,7 @@ #include "absl/debugging/symbolize_win32.inc" #elif defined(__APPLE__) #include "absl/debugging/symbolize_darwin.inc" -#elif defined(__EMSCRIPTEN__) +#elif defined(ABSL_INTERNAL_HAVE_SYMBOLIZE_WASM) #include "absl/debugging/symbolize_emscripten.inc" #else #include "absl/debugging/symbolize_unimplemented.inc" diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h index 4ae07c2d..e977fc67 100644 --- a/absl/strings/numbers.h +++ b/absl/strings/numbers.h @@ -181,16 +181,19 @@ char* FastIntToBuffer(int_type i, char* buffer) { // TODO(jorg): This signed-ness check is used because it works correctly // with enums, and it also serves to check that int_type is not a pointer. // If one day something like std::is_signed works, switch to it. - if (static_cast(1) - 2 < 0) { // Signed - if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit + // These conditions are constexpr bools to suppress MSVC warning C4127. + constexpr bool kIsSigned = static_cast(1) - 2 < 0; + constexpr bool kUse64Bit = sizeof(i) > 32 / 8; + if (kIsSigned) { + if (kUse64Bit) { return FastIntToBuffer(static_cast(i), buffer); - } else { // 32-bit or less + } else { return FastIntToBuffer(static_cast(i), buffer); } - } else { // Unsigned - if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit + } else { + if (kUse64Bit) { return FastIntToBuffer(static_cast(i), buffer); - } else { // 32-bit or less + } else { return FastIntToBuffer(static_cast(i), buffer); } } @@ -209,22 +212,25 @@ ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, int_type* out, // TODO(jorg): This signed-ness check is used because it works correctly // with enums, and it also serves to check that int_type is not a pointer. // If one day something like std::is_signed works, switch to it. - if (static_cast(1) - 2 < 0) { // Signed - if (sizeof(*out) == 64 / 8) { // 64-bit + // These conditions are constexpr bools to suppress MSVC warning C4127. + constexpr bool kIsSigned = static_cast(1) - 2 < 0; + constexpr bool kUse64Bit = sizeof(*out) == 64 / 8; + if (kIsSigned) { + if (kUse64Bit) { int64_t val; parsed = numbers_internal::safe_strto64_base(s, &val, base); *out = static_cast(val); - } else { // 32-bit + } else { int32_t val; parsed = numbers_internal::safe_strto32_base(s, &val, base); *out = static_cast(val); } - } else { // Unsigned - if (sizeof(*out) == 64 / 8) { // 64-bit + } else { + if (kUse64Bit) { uint64_t val; parsed = numbers_internal::safe_strtou64_base(s, &val, base); *out = static_cast(val); - } else { // 32-bit + } else { uint32_t val; parsed = numbers_internal::safe_strtou32_base(s, &val, base); *out = static_cast(val); -- cgit v1.2.3 From d587c966ed86dc3b94362444e2b20fc3c5c4224e Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 15 Nov 2021 11:29:23 -0800 Subject: Export of internal Abseil changes -- 355b8f7b0070b005d53d94ee4180e95559ba2c88 by Derek Mauro : Documentation: don't define absl::Status::ok() in terms of itself Fixes #1058 PiperOrigin-RevId: 410035651 -- 31c512c834b3a8979297adc5006c3727a3c6554b by Evan Brown : Cleanup: move set_params/set_slot_policy into btree_set.h and move map_params into btree_map.h. Also change some `sizeof(value_type)`s to `sizeof(slot_type)`s and update some comments/variable names referring to values to refer to slots as appropriate in btree.h. Motivation: preliminary cleanup towards node_btree_*. PiperOrigin-RevId: 409991342 -- 3129ca320d61a82f1c9ee8c02a23d25024eea4ab by Abseil Team : Use simpler implementation for AddressIsReadable. In particular, current solution doesn't work on systems configured with large pid_t space. PiperOrigin-RevId: 409397716 -- f71067f7494b19ce4a2e1df730b934dc931c51b2 by Martijn Vels : Add Span dependency PiperOrigin-RevId: 409198889 GitOrigin-RevId: 355b8f7b0070b005d53d94ee4180e95559ba2c88 Change-Id: I7f4df3ec7739fdfde61d8ba983f07a08f6f1c7d7 --- absl/container/btree_map.h | 60 ++++++++++++ absl/container/btree_set.h | 74 ++++++++++++++ absl/container/internal/btree.h | 122 ++---------------------- absl/debugging/internal/address_is_readable.cc | 127 +++++++++---------------- absl/status/status.h | 5 +- absl/strings/BUILD.bazel | 1 + absl/strings/CMakeLists.txt | 1 + 7 files changed, 195 insertions(+), 195 deletions(-) (limited to 'absl/debugging') diff --git a/absl/container/btree_map.h b/absl/container/btree_map.h index 96ebcb77..4eafe062 100644 --- a/absl/container/btree_map.h +++ b/absl/container/btree_map.h @@ -56,6 +56,14 @@ namespace absl { ABSL_NAMESPACE_BEGIN +namespace container_internal { + +template +struct map_params; + +} // namespace container_internal + // absl::btree_map<> // // An `absl::btree_map` is an ordered associative container of @@ -812,6 +820,58 @@ void erase_if(btree_multimap &map, Pred pred) { } } +namespace container_internal { + +// A parameters structure for holding the type parameters for a btree_map. +// Compare and Alloc should be nothrow copy-constructible. +template +struct map_params : common_params> { + using super_type = typename map_params::common_params; + using mapped_type = Data; + // This type allows us to move keys when it is safe to do so. It is safe + // for maps in which value_type and mutable_value_type are layout compatible. + using slot_policy = typename super_type::slot_policy; + using slot_type = typename super_type::slot_type; + using value_type = typename super_type::value_type; + using init_type = typename super_type::init_type; + + using original_key_compare = typename super_type::original_key_compare; + // Reference: https://en.cppreference.com/w/cpp/container/map/value_compare + class value_compare { + template + friend class btree; + + protected: + explicit value_compare(original_key_compare c) : comp(std::move(c)) {} + + original_key_compare comp; // NOLINT + + public: + auto operator()(const value_type &lhs, const value_type &rhs) const + -> decltype(comp(lhs.first, rhs.first)) { + return comp(lhs.first, rhs.first); + } + }; + using is_map_container = std::true_type; + + template + static auto key(const V &value) -> decltype(value.first) { + return value.first; + } + static const Key &key(const slot_type *s) { return slot_policy::key(s); } + static const Key &key(slot_type *s) { return slot_policy::key(s); } + // For use in node handle. + static auto mutable_key(slot_type *s) + -> decltype(slot_policy::mutable_key(s)) { + return slot_policy::mutable_key(s); + } + static mapped_type &value(value_type *value) { return value->second; } +}; + +} // namespace container_internal + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/container/btree_set.h b/absl/container/btree_set.h index f587ca22..8c96e0ed 100644 --- a/absl/container/btree_set.h +++ b/absl/container/btree_set.h @@ -55,6 +55,17 @@ namespace absl { ABSL_NAMESPACE_BEGIN +namespace container_internal { + +template +struct set_slot_policy; + +template +struct set_params; + +} // namespace container_internal + // absl::btree_set<> // // An `absl::btree_set` is an ordered associative container of unique key @@ -724,6 +735,69 @@ void erase_if(btree_multiset &set, Pred pred) { } } +namespace container_internal { + +// This type implements the necessary functions from the +// absl::container_internal::slot_type interface for btree_(multi)set. +template +struct set_slot_policy { + using slot_type = Key; + using value_type = Key; + using mutable_value_type = Key; + + static value_type &element(slot_type *slot) { return *slot; } + static const value_type &element(const slot_type *slot) { return *slot; } + + template + static void construct(Alloc *alloc, slot_type *slot, Args &&...args) { + absl::allocator_traits::construct(*alloc, slot, + std::forward(args)...); + } + + template + static void construct(Alloc *alloc, slot_type *slot, slot_type *other) { + absl::allocator_traits::construct(*alloc, slot, std::move(*other)); + } + + template + static void destroy(Alloc *alloc, slot_type *slot) { + absl::allocator_traits::destroy(*alloc, slot); + } + + template + static void swap(Alloc * /*alloc*/, slot_type *a, slot_type *b) { + using std::swap; + swap(*a, *b); + } + + template + static void move(Alloc * /*alloc*/, slot_type *src, slot_type *dest) { + *dest = std::move(*src); + } +}; + +// A parameters structure for holding the type parameters for a btree_set. +// Compare and Alloc should be nothrow copy-constructible. +template +struct set_params : common_params> { + using value_type = Key; + using slot_type = typename set_params::common_params::slot_type; + using value_compare = + typename set_params::common_params::original_key_compare; + using is_map_container = std::false_type; + + template + static const V &key(const V &value) { + return value; + } + static const Key &key(const slot_type *slot) { return *slot; } + static const Key &key(slot_type *slot) { return *slot; } +}; + +} // namespace container_internal + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/container/internal/btree.h b/absl/container/internal/btree.h index f636c5fc..bf65a03d 100644 --- a/absl/container/internal/btree.h +++ b/absl/container/internal/btree.h @@ -270,17 +270,17 @@ struct common_params { enum { kTargetNodeSize = TargetNodeSize, - // Upper bound for the available space for values. This is largest for leaf + // Upper bound for the available space for slots. This is largest for leaf // nodes, which have overhead of at least a pointer + 4 bytes (for storing // 3 field_types and an enum). - kNodeValueSpace = + kNodeSlotSpace = TargetNodeSize - /*minimum overhead=*/(sizeof(void *) + 4), }; - // This is an integral type large enough to hold as many - // ValueSize-values as will fit a node of TargetNodeSize bytes. + // This is an integral type large enough to hold as many slots as will fit a + // node of TargetNodeSize bytes. using node_count_type = - absl::conditional_t<(kNodeValueSpace / sizeof(value_type) > + absl::conditional_t<(kNodeSlotSpace / sizeof(slot_type) > (std::numeric_limits::max)()), uint16_t, uint8_t>; // NOLINT @@ -314,111 +314,6 @@ struct common_params { } }; -// A parameters structure for holding the type parameters for a btree_map. -// Compare and Alloc should be nothrow copy-constructible. -template -struct map_params : common_params> { - using super_type = typename map_params::common_params; - using mapped_type = Data; - // This type allows us to move keys when it is safe to do so. It is safe - // for maps in which value_type and mutable_value_type are layout compatible. - using slot_policy = typename super_type::slot_policy; - using slot_type = typename super_type::slot_type; - using value_type = typename super_type::value_type; - using init_type = typename super_type::init_type; - - using original_key_compare = typename super_type::original_key_compare; - // Reference: https://en.cppreference.com/w/cpp/container/map/value_compare - class value_compare { - template - friend class btree; - - protected: - explicit value_compare(original_key_compare c) : comp(std::move(c)) {} - - original_key_compare comp; // NOLINT - - public: - auto operator()(const value_type &lhs, const value_type &rhs) const - -> decltype(comp(lhs.first, rhs.first)) { - return comp(lhs.first, rhs.first); - } - }; - using is_map_container = std::true_type; - - template - static auto key(const V &value) -> decltype(value.first) { - return value.first; - } - static const Key &key(const slot_type *s) { return slot_policy::key(s); } - static const Key &key(slot_type *s) { return slot_policy::key(s); } - // For use in node handle. - static auto mutable_key(slot_type *s) - -> decltype(slot_policy::mutable_key(s)) { - return slot_policy::mutable_key(s); - } - static mapped_type &value(value_type *value) { return value->second; } -}; - -// This type implements the necessary functions from the -// absl::container_internal::slot_type interface. -template -struct set_slot_policy { - using slot_type = Key; - using value_type = Key; - using mutable_value_type = Key; - - static value_type &element(slot_type *slot) { return *slot; } - static const value_type &element(const slot_type *slot) { return *slot; } - - template - static void construct(Alloc *alloc, slot_type *slot, Args &&... args) { - absl::allocator_traits::construct(*alloc, slot, - std::forward(args)...); - } - - template - static void construct(Alloc *alloc, slot_type *slot, slot_type *other) { - absl::allocator_traits::construct(*alloc, slot, std::move(*other)); - } - - template - static void destroy(Alloc *alloc, slot_type *slot) { - absl::allocator_traits::destroy(*alloc, slot); - } - - template - static void swap(Alloc * /*alloc*/, slot_type *a, slot_type *b) { - using std::swap; - swap(*a, *b); - } - - template - static void move(Alloc * /*alloc*/, slot_type *src, slot_type *dest) { - *dest = std::move(*src); - } -}; - -// A parameters structure for holding the type parameters for a btree_set. -// Compare and Alloc should be nothrow copy-constructible. -template -struct set_params : common_params> { - using value_type = Key; - using slot_type = typename set_params::common_params::slot_type; - using value_compare = - typename set_params::common_params::original_key_compare; - using is_map_container = std::false_type; - - template - static const V &key(const V &value) { return value; } - static const Key &key(const slot_type *slot) { return *slot; } - static const Key &key(slot_type *slot) { return *slot; } -}; - // An adapter class that converts a lower-bound compare into an upper-bound // compare. Note: there is no need to make a version of this adapter specialized // for key-compare-to functors because the upper-bound (the first value greater @@ -562,9 +457,9 @@ class btree_node { /*children*/ 0) .AllocSize(); } - // A lower bound for the overhead of fields other than values in a leaf node. + // A lower bound for the overhead of fields other than slots in a leaf node. constexpr static size_type MinimumOverhead() { - return SizeWithNSlots(1) - sizeof(value_type); + return SizeWithNSlots(1) - sizeof(slot_type); } // Compute how many values we can fit onto a leaf node taking into account @@ -1397,6 +1292,7 @@ class btree { } // The total number of bytes used by the btree. + // TODO(b/169338300): update to support node_btree_*. size_type bytes_used() const { node_stats stats = internal_stats(root()); if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) { @@ -1929,7 +1825,7 @@ constexpr bool btree

::static_assert_validation() { "key comparison function must return absl::{weak,strong}_ordering or " "bool."); - // Test the assumption made in setting kNodeValueSpace. + // Test the assumption made in setting kNodeSlotSpace. static_assert(node_type::MinimumOverhead() >= sizeof(void *) + 4, "node space assumption incorrect"); diff --git a/absl/debugging/internal/address_is_readable.cc b/absl/debugging/internal/address_is_readable.cc index 329c285f..26df3289 100644 --- a/absl/debugging/internal/address_is_readable.cc +++ b/absl/debugging/internal/address_is_readable.cc @@ -33,12 +33,12 @@ ABSL_NAMESPACE_END #else #include +#include #include +#include #include -#include #include -#include #include "absl/base/internal/errno_saver.h" #include "absl/base/internal/raw_logging.h" @@ -47,89 +47,56 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { -// Pack a pid and two file descriptors into a 64-bit word, -// using 16, 24, and 24 bits for each respectively. -static uint64_t Pack(uint64_t pid, uint64_t read_fd, uint64_t write_fd) { - ABSL_RAW_CHECK((read_fd >> 24) == 0 && (write_fd >> 24) == 0, - "fd out of range"); - return (pid << 48) | ((read_fd & 0xffffff) << 24) | (write_fd & 0xffffff); -} - -// Unpack x into a pid and two file descriptors, where x was created with -// Pack(). -static void Unpack(uint64_t x, int *pid, int *read_fd, int *write_fd) { - *pid = x >> 48; - *read_fd = (x >> 24) & 0xffffff; - *write_fd = x & 0xffffff; -} - -// Return whether the byte at *addr is readable, without faulting. -// Save and restores errno. Returns true on systems where -// unimplemented. -// This is a namespace-scoped variable for correct zero-initialization. -static std::atomic pid_and_fds; // initially 0, an invalid pid. - bool AddressIsReadable(const void *addr) { + int fd = 0; absl::base_internal::ErrnoSaver errno_saver; - // We test whether a byte is readable by using write(). Normally, this would - // be done via a cached file descriptor to /dev/null, but linux fails to - // check whether the byte is readable when the destination is /dev/null, so - // we use a cached pipe. We store the pid of the process that created the - // pipe to handle the case where a process forks, and the child closes all - // the file descriptors and then calls this routine. This is not perfect: - // the child could use the routine, then close all file descriptors and then - // use this routine again. But the likely use of this routine is when - // crashing, to test the validity of pages when dumping the stack. Beware - // that we may leak file descriptors, but we're unlikely to leak many. - int bytes_written; - int current_pid = getpid() & 0xffff; // we use only the low order 16 bits - do { // until we do not get EBADF trying to use file descriptors - int pid; - int read_fd; - int write_fd; - uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire); - Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd); - while (current_pid != pid) { - int p[2]; - // new pipe - if (pipe(p) != 0) { - ABSL_RAW_LOG(FATAL, "Failed to create pipe, errno=%d", errno); - } - fcntl(p[0], F_SETFD, FD_CLOEXEC); - fcntl(p[1], F_SETFD, FD_CLOEXEC); - uint64_t new_pid_and_fds = Pack(current_pid, p[0], p[1]); - if (pid_and_fds.compare_exchange_strong( - local_pid_and_fds, new_pid_and_fds, std::memory_order_release, - std::memory_order_relaxed)) { - local_pid_and_fds = new_pid_and_fds; // fds exposed to other threads - } else { // fds not exposed to other threads; we can close them. - close(p[0]); - close(p[1]); - local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire); - } - Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd); - } - errno = 0; - // Use syscall(SYS_write, ...) instead of write() to prevent ASAN - // and other checkers from complaining about accesses to arbitrary - // memory. + for (int j = 0; j < 2; j++) { + // Here we probe with some syscall which + // - accepts a one-byte region of user memory as input + // - tests for EFAULT before other validation + // - has no problematic side-effects + // + // connect(2) works for this. It copies the address into kernel + // memory before any validation beyond requiring an open fd. + // But a one byte address is never valid (sa_family is two bytes), + // so the call cannot succeed and change any state. + // + // This strategy depends on Linux implementation details, + // so we rely on the test to alert us if it stops working. + // + // Some discarded past approaches: + // - msync() doesn't reject PROT_NONE regions + // - write() on /dev/null doesn't return EFAULT + // - write() on a pipe requires creating it and draining the writes + // + // Use syscall(SYS_connect, ...) instead of connect() to prevent ASAN + // and other checkers from complaining about accesses to arbitrary memory. do { - bytes_written = syscall(SYS_write, write_fd, addr, 1); - } while (bytes_written == -1 && errno == EINTR); - if (bytes_written == 1) { // remove the byte from the pipe - char c; - while (read(read_fd, &c, 1) == -1 && errno == EINTR) { + ABSL_RAW_CHECK(syscall(SYS_connect, fd, addr, 1) == -1, + "should never succeed"); + } while (errno == EINTR); + if (errno == EFAULT) return false; + if (errno == EBADF) { + if (j != 0) { + // Unclear what happened. + ABSL_RAW_LOG(ERROR, "unexpected EBADF on fd %d", fd); + return false; } + // fd 0 must have been closed. Try opening it again. + // Note: we shouldn't leak too many file descriptors here, since we expect + // to get fd==0 reopened. + fd = open("/dev/null", O_RDONLY); + if (fd == -1) { + ABSL_RAW_LOG(ERROR, "can't open /dev/null"); + return false; + } + } else { + // probably EINVAL or ENOTSOCK; we got past EFAULT validation. + return true; } - if (errno == EBADF) { // Descriptors invalid. - // If pid_and_fds contains the problematic file descriptors we just used, - // this call will forget them, and the loop will try again. - pid_and_fds.compare_exchange_strong(local_pid_and_fds, 0, - std::memory_order_release, - std::memory_order_relaxed); - } - } while (errno == EBADF); - return bytes_written == 1; + } + ABSL_RAW_CHECK(false, "unreachable"); + return false; } } // namespace debugging_internal diff --git a/absl/status/status.h b/absl/status/status.h index 39071e5f..5a09faeb 100644 --- a/absl/status/status.h +++ b/absl/status/status.h @@ -469,8 +469,9 @@ class Status final { // Status::ok() // - // Returns `true` if `this->ok()`. Prefer checking for an OK status using this - // member function. + // Returns `true` if `this->code()` == `absl::StatusCode::kOk`, + // indicating the absence of an error. + // Prefer checking for an OK status using this member function. ABSL_MUST_USE_RESULT bool ok() const; // Status::code() diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 0c47ca54..4e37151e 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -437,6 +437,7 @@ cc_library( "//absl/functional:function_ref", "//absl/meta:type_traits", "//absl/types:optional", + "//absl/types:span", ], ) diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index aab97efd..0eef91df 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -851,6 +851,7 @@ absl_cc_library( absl::inlined_vector absl::optional absl::raw_logging_internal + absl::span absl::strings absl::type_traits PUBLIC -- cgit v1.2.3 From 1065514ef332d036f3437e950e78d35ce6b7c740 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 13 Dec 2021 14:47:02 -0800 Subject: Export of internal Abseil changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -- 07240ca7822d007cdcc79f2c40bd58b2c2010348 by Abseil Team : Correct the comment from "AlphaNum" to "Arg". PiperOrigin-RevId: 416139192 -- adcba4a6b3763626e1db7b1e8c108b3114903557 by Martijn Vels : Fix NewExternalRep() to require data being non-empty, and remove nullptr return. PiperOrigin-RevId: 416135865 -- c0d14cd918fb16f15d1d84de9284b5c5ecc1f8f2 by Abseil Team : Fix doc comment for absl::ascii_isprint(). The comment was incorrectly saying that it includes all whitespace. It doesn't; the only whitespace char it includes is ' '. PiperOrigin-RevId: 416112524 -- d83327800159c07002b6865e21232a12463e02dd by Abseil Team : Internal change PiperOrigin-RevId: 416099978 -- baf11e9ca42ca9140cdbf8075f971db8d65b1195 by Ilya Tokar : Prevent compiler from optimizing Group_Match* benchmarks away. Currently we benchmark single store of precomputed value. Not all affected benchmarks show performance changes: BM_Group_Match 0.53ns ± 1% 0.53ns ± 0% -0.42% (p=0.038 n=10+10) BM_Group_MatchEmpty 0.26ns ± 1% 0.26ns ± 1% ~ (p=1.000 n=10+10) BM_Group_MatchEmptyOrDeleted 0.26ns ± 1% 0.26ns ± 1% ~ (p=0.121 n=10+10) BM_Group_CountLeadingEmptyOrDeleted 0.26ns ± 1% 0.45ns ± 0% +70.05% (p=0.000 n=10+8) BM_Group_MatchFirstEmptyOrDeleted 0.26ns ± 0% 0.44ns ± 1% +65.91% (p=0.000 n=8+9) But inspecting the generated code shows the difference, e. g. BM_Group_MatchFirstEmptyOrDeleted Before: add $0xffffffffffffffff,%rbx jne 30 After: pcmpeqd %xmm0,%xmm0 pcmpgtb -0x30(%rbp),%xmm0 pmovmskb %xmm0,%eax add: 0x23$0xffffffffffffffff,%rbx jne 40 PiperOrigin-RevId: 416083515 -- 122fbff893dc4571b3e75e4b241eb4495b925610 by Abseil Team : Put namespace guard in ABSL_DECLARE_FLAG to make declaring a flag in a namespace a compiler error instead of a linker error. PiperOrigin-RevId: 416036072 -- 020fd8a20f5fa319e948846e003391fcb9e03868 by Ilya Tokar : Make Cord::InlineRep::set_data unconditionally zero out memory. Currently there is a single case where we don't zero out memory as an optimization. Unconditional zeroing doesn't show any changes in benchmarks, except for the unrelated improvement: BM_CordPartialCopyToCord/1M/1 12.6ns ± 4% 12.6ns ± 4% ~ (p=0.857 n=16+19) BM_CordPartialCopyToCord/1M/128 44.9ns ± 7% 45.0ns ± 3% ~ (p=0.468 n=18+17) BM_CordPartialCopyToCord/1M/1k 64.5ns ± 4% 61.4ns ± 4% -4.82% (p=0.000 n=19+17) BM_CordPartialCopyToCord/1M/8k 139ns ± 3% 128ns ±15% -7.76% (p=0.009 n=17+20) BM_CordPartialCopyToCord/1M/16k 193ns ± 6% 168ns ± 6% -13.17% (p=0.000 n=17+17) BM_CordPartialCopyToCord/4M/16k 199ns ± 4% 177ns ± 4% -11.36% (p=0.000 n=17+18) BM_CordPartialCopyToCord/4M/32k 275ns ± 3% 250ns ± 4% -9.00% (p=0.000 n=18+18) BM_CordPartialCopyToCord/4M/64k 291ns ± 4% 266ns ± 5% -8.53% (p=0.000 n=18+16) BM_CordPartialCopyToCord/4M/128k 322ns ± 5% 291ns ± 4% -9.43% (p=0.000 n=20+18) BM_CordPartialCopyToCord/8M/32k 281ns ± 5% 251ns ± 4% -10.38% (p=0.000 n=20+16) BM_CordPartialCopyToCord/8M/64k 293ns ± 6% 267ns ± 4% -8.87% (p=0.000 n=16+19) BM_CordPartialCopyToCord/8M/128k 334ns ± 3% 305ns ± 2% -8.56% (p=0.000 n=17+16) This is clearly an alignmnet effect since number of the executed instructions is the same: M_CordPartialCopyToCord/1M/1 155 ± 0% 155 ± 0% ~ (all samples are equal) BM_CordPartialCopyToCord/1M/128 446 ± 0% 446 ± 0% ~ (p=0.332 n=36+39) BM_CordPartialCopyToCord/1M/1k 473 ± 0% 473 ± 0% ~ (p=0.969 n=40+40) BM_CordPartialCopyToCord/1M/8k 808 ± 0% 808 ± 0% ~ (p=0.127 n=40+39) BM_CordPartialCopyToCord/1M/16k 957 ± 0% 957 ± 0% ~ (p=0.532 n=40+40) BM_CordPartialCopyToCord/4M/16k 952 ± 0% 952 ± 0% ~ (p=0.686 n=39+39) BM_CordPartialCopyToCord/4M/32k 1.12k ± 0% 1.12k ± 0% ~ (p=0.690 n=40+40) BM_CordPartialCopyToCord/4M/64k 1.23k ± 0% 1.23k ± 0% ~ (p=0.182 n=40+39) BM_CordPartialCopyToCord/4M/128k 1.44k ± 0% 1.44k ± 0% ~ (p=0.711 n=40+40) BM_CordPartialCopyToCord/8M/32k 1.12k ± 0% 1.12k ± 0% ~ (p=0.697 n=40+40) BM_CordPartialCopyToCord/8M/64k 1.23k ± 0% 1.23k ± 0% +0.00% (p=0.049 n=40+40) BM_CordPartialCopyToCord/8M/128k 1.44k ± 0% 1.44k ± 0% ~ (p=0.507 n=40+40) This makes code simpler and doesn't regress performance. PiperOrigin-RevId: 415560574 -- 37305b2690b31682088749e4d62f40d7095bdc54 by Derek Mauro : Internal change PiperOrigin-RevId: 415558737 -- 86aaed569b9e743c1eb813a5f48def978a793db3 by Martijn Vels : Internal change PiperOrigin-RevId: 415515201 -- 6cdb8786cdcb4fa0b8a4b72fc98940877d1fdeff by Abseil Team : Update SubmitMutexProfileData to accept wait_cycles instead of wait_timestamp PiperOrigin-RevId: 415360871 -- 9f979d307aa16ad09f214e04876cbe84395c0901 by Abseil Team : absl::flat_hash_set compiles with -Wconversion -Wsign-compare PiperOrigin-RevId: 415357498 -- 9eceb14174708f15e61259d449b214a8a4c7f9e7 by Abseil Team : Fix AddressIsReadable for the corner case of (aligned) addr == NULL. PiperOrigin-RevId: 415307792 -- 1a39ffe55898375e2d7f88c17c99db5a1b95b313 by Martijn Vels : Internal change PiperOrigin-RevId: 415162872 -- 64378549b110d5f5762185a5906c520fba70f0e7 by Abseil Team : Fix a typo in the comments PiperOrigin-RevId: 415088461 -- 41aae8322e913b82710153c22b97c611fdb6e1fb by Abseil Team : Switch from `connect` to `rt_sigreturn` -- the latter is much less problematic for system call sandboxes. PiperOrigin-RevId: 415073965 -- 870c5e3388b6a35611bff538626fe7a1c8c87171 by Abseil Team : Add ABSL_HAVE_HWADDRESS_SANITIZER and ABSL_HAVE_LEAK_SANITIZER PiperOrigin-RevId: 414871189 -- f213ed60a66b58da7ac40555adfb1d529ff0a4db by Derek Mauro : Remove reference to __SANITIZE_MEMORY__, which does not exist It appears to have been copied by pattern matching from the ASAN/TSAN code blocks. https://github.com/gcc-mirror/gcc/blob/f47662204de27f7685699eeef89aa173ccf32d85/gcc/cppbuiltin.c#L79-L126 PiperOrigin-RevId: 414806587 -- b152891e73ab515f397ceb53f66c8ee2f33863ea by Abseil Team : Rollback previous commit: SYS_open is not defined in certain environments. PiperOrigin-RevId: 414521820 -- 5a1cbb282331023902e1374dd0d920c4effbe47f by Abseil Team : Use syscall(SYS_open, ...) instead of open() to avoid possible symbol interposition. Also add some warning notes. PiperOrigin-RevId: 414508186 -- 1824d6593612710aafdc599a89b0adced7d787f6 by Abseil Team : Correct aarch64 macro check The macro is __aarch64__, not __arch64__. PiperOrigin-RevId: 414446225 -- a1536a57b64dfd53945d33a01cfc08b18c99c97b by Abseil Team : Fix backwards comment in the last commit. PiperOrigin-RevId: 414281214 -- 11ac021ba779513667a31cf2563ddafc57d6d913 by Abseil Team : AddressIsReadable() didn't work correctly on ARM when the given pointer was misaligned at the end of the page. Fix that by aligning the pointer on an 8-byte boundary before checking it. PiperOrigin-RevId: 414203863 GitOrigin-RevId: 07240ca7822d007cdcc79f2c40bd58b2c2010348 Change-Id: If5f129194d59f5c9e5d84efd8cd9e17a70e072ab --- absl/base/config.h | 24 ++++- absl/base/internal/direct_mmap.h | 2 +- absl/container/internal/raw_hash_set.h | 27 +++--- absl/container/internal/raw_hash_set_benchmark.cc | 20 ++++- absl/debugging/internal/address_is_readable.cc | 102 ++++++++++------------ absl/flags/declare.h | 6 +- absl/random/internal/randen_detect.cc | 1 - absl/strings/ascii.h | 2 +- absl/strings/cord.cc | 19 ++-- absl/strings/cord.h | 34 ++++---- absl/strings/cord_test.cc | 77 +++++++++++----- absl/strings/substitute.h | 4 +- absl/synchronization/mutex.cc | 2 +- absl/synchronization/notification.h | 2 +- 14 files changed, 189 insertions(+), 133 deletions(-) (limited to 'absl/debugging') diff --git a/absl/base/config.h b/absl/base/config.h index c29b206a..373aa0cc 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -751,8 +751,6 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // a compiler instrumentation module and a run-time library. #ifdef ABSL_HAVE_MEMORY_SANITIZER #error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set." -#elif defined(__SANITIZE_MEMORY__) -#define ABSL_HAVE_MEMORY_SANITIZER 1 #elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer) #define ABSL_HAVE_MEMORY_SANITIZER 1 #endif @@ -779,6 +777,28 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #define ABSL_HAVE_ADDRESS_SANITIZER 1 #endif +// ABSL_HAVE_HWADDRESS_SANITIZER +// +// Hardware-Assisted AddressSanitizer (or HWASAN) is even faster than asan +// memory error detector which can use CPU features like ARM TBI, Intel LAM or +// AMD UAI. +#ifdef ABSL_HAVE_HWADDRESS_SANITIZER +#error "ABSL_HAVE_HWADDRESS_SANITIZER cannot be directly set." +#elif defined(__SANITIZE_HWADDRESS__) +#define ABSL_HAVE_HWADDRESS_SANITIZER 1 +#elif ABSL_HAVE_FEATURE(hwaddress_sanitizer) +#define ABSL_HAVE_HWADDRESS_SANITIZER 1 +#endif + +// ABSL_HAVE_LEAK_SANITIZER +// +// LeakSanitizer (or lsan) is a detector of memory leaks. +#ifdef ABSL_HAVE_LEAK_SANITIZER +#error "ABSL_HAVE_LEAK_SANITIZER cannot be directly set." +#elif ABSL_HAVE_FEATURE(leak_sanitizer) +#define ABSL_HAVE_LEAK_SANITIZER 1 +#endif + // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION // // Class template argument deduction is a language feature added in C++17. diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h index 274054cd..7037094b 100644 --- a/absl/base/internal/direct_mmap.h +++ b/absl/base/internal/direct_mmap.h @@ -80,7 +80,7 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, (defined(__PPC__) && !defined(__PPC64__)) || \ (defined(__riscv) && __riscv_xlen == 32) || \ (defined(__s390__) && !defined(__s390x__)) || \ - (defined(__sparc__) && !defined(__arch64__)) + (defined(__sparc__) && !defined(__aarch64__)) // On these architectures, implement mmap with mmap2. static int pagesize = 0; if (pagesize == 0) { diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index d4b72ab1..ad12f41c 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -201,7 +201,7 @@ constexpr bool IsNoThrowSwappable(std::false_type /* is_swappable */) { template uint32_t TrailingZeros(T x) { ABSL_INTERNAL_ASSUME(x != 0); - return countr_zero(x); + return static_cast(countr_zero(x)); } // An abstraction over a bitmask. It provides an easy way to iterate through the @@ -230,7 +230,7 @@ class BitMask { return *this; } explicit operator bool() const { return mask_ != 0; } - int operator*() const { return LowestBitSet(); } + uint32_t operator*() const { return LowestBitSet(); } uint32_t LowestBitSet() const { return container_internal::TrailingZeros(mask_) >> Shift; } @@ -248,7 +248,7 @@ class BitMask { uint32_t LeadingZeros() const { constexpr int total_significant_bits = SignificantBits << Shift; constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits; - return countl_zero(mask_ << extra_bits) >> Shift; + return static_cast(countl_zero(mask_ << extra_bits)) >> Shift; } private: @@ -360,7 +360,7 @@ struct GroupSse2Impl { BitMask Match(h2_t hash) const { auto match = _mm_set1_epi8(hash); return BitMask( - _mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl))); + static_cast(_mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl)))); } // Returns a bitmask representing the positions of empty slots. @@ -368,7 +368,7 @@ struct GroupSse2Impl { #if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 // This only works because ctrl_t::kEmpty is -128. return BitMask( - _mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl))); + static_cast(_mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl)))); #else return Match(static_cast(ctrl_t::kEmpty)); #endif @@ -376,14 +376,15 @@ struct GroupSse2Impl { // Returns a bitmask representing the positions of empty or deleted slots. BitMask MatchEmptyOrDeleted() const { - auto special = _mm_set1_epi8(static_cast(ctrl_t::kSentinel)); + auto special = _mm_set1_epi8(static_cast(ctrl_t::kSentinel)); return BitMask( - _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))); + static_cast( + _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)))); } // Returns the number of trailing empty or deleted elements in the group. uint32_t CountLeadingEmptyOrDeleted() const { - auto special = _mm_set1_epi8(static_cast(ctrl_t::kSentinel)); + auto special = _mm_set1_epi8(static_cast(ctrl_t::kSentinel)); return TrailingZeros(static_cast( _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1)); } @@ -1465,7 +1466,7 @@ class raw_hash_set { auto seq = probe(ctrl_, hash, capacity_); while (true) { Group g{ctrl_ + seq.offset()}; - for (int i : g.Match(H2(hash))) { + for (uint32_t i : g.Match(H2(hash))) { if (ABSL_PREDICT_TRUE(PolicyTraits::apply( EqualElement{key, eq_ref()}, PolicyTraits::element(slots_ + seq.offset(i))))) @@ -1610,7 +1611,7 @@ class raw_hash_set { void erase_meta_only(const_iterator it) { assert(IsFull(*it.inner_.ctrl_) && "erasing a dangling iterator"); --size_; - const size_t index = it.inner_.ctrl_ - ctrl_; + const size_t index = static_cast(it.inner_.ctrl_ - ctrl_); const size_t index_before = (index - Group::kWidth) & capacity_; const auto empty_after = Group(it.inner_.ctrl_).MatchEmpty(); const auto empty_before = Group(ctrl_ + index_before).MatchEmpty(); @@ -1832,7 +1833,7 @@ class raw_hash_set { auto seq = probe(ctrl_, hash, capacity_); while (true) { Group g{ctrl_ + seq.offset()}; - for (int i : g.Match(H2(hash))) { + for (uint32_t i : g.Match(H2(hash))) { if (ABSL_PREDICT_TRUE(PolicyTraits::element(slots_ + seq.offset(i)) == elem)) return true; @@ -1864,7 +1865,7 @@ class raw_hash_set { auto seq = probe(ctrl_, hash, capacity_); while (true) { Group g{ctrl_ + seq.offset()}; - for (int i : g.Match(H2(hash))) { + for (uint32_t i : g.Match(H2(hash))) { if (ABSL_PREDICT_TRUE(PolicyTraits::apply( EqualElement{key, eq_ref()}, PolicyTraits::element(slots_ + seq.offset(i))))) @@ -1984,7 +1985,7 @@ struct HashtableDebugAccess> { auto seq = probe(set.ctrl_, hash, set.capacity_); while (true) { container_internal::Group g{set.ctrl_ + seq.offset()}; - for (int i : g.Match(container_internal::H2(hash))) { + for (uint32_t i : g.Match(container_internal::H2(hash))) { if (Traits::apply( typename Set::template EqualElement{ key, set.eq_ref()}, diff --git a/absl/container/internal/raw_hash_set_benchmark.cc b/absl/container/internal/raw_hash_set_benchmark.cc index c886d3ad..146ef433 100644 --- a/absl/container/internal/raw_hash_set_benchmark.cc +++ b/absl/container/internal/raw_hash_set_benchmark.cc @@ -330,6 +330,7 @@ void BM_Group_Match(benchmark::State& state) { h2_t h = 1; for (auto _ : state) { ::benchmark::DoNotOptimize(h); + ::benchmark::DoNotOptimize(g); ::benchmark::DoNotOptimize(g.Match(h)); } } @@ -339,7 +340,10 @@ void BM_Group_MatchEmpty(benchmark::State& state) { std::array group; Iota(group.begin(), group.end(), -4); Group g{group.data()}; - for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmpty()); + for (auto _ : state) { + ::benchmark::DoNotOptimize(g); + ::benchmark::DoNotOptimize(g.MatchEmpty()); + } } BENCHMARK(BM_Group_MatchEmpty); @@ -347,7 +351,10 @@ void BM_Group_MatchEmptyOrDeleted(benchmark::State& state) { std::array group; Iota(group.begin(), group.end(), -4); Group g{group.data()}; - for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmptyOrDeleted()); + for (auto _ : state) { + ::benchmark::DoNotOptimize(g); + ::benchmark::DoNotOptimize(g.MatchEmptyOrDeleted()); + } } BENCHMARK(BM_Group_MatchEmptyOrDeleted); @@ -355,8 +362,10 @@ void BM_Group_CountLeadingEmptyOrDeleted(benchmark::State& state) { std::array group; Iota(group.begin(), group.end(), -2); Group g{group.data()}; - for (auto _ : state) + for (auto _ : state) { + ::benchmark::DoNotOptimize(g); ::benchmark::DoNotOptimize(g.CountLeadingEmptyOrDeleted()); + } } BENCHMARK(BM_Group_CountLeadingEmptyOrDeleted); @@ -364,7 +373,10 @@ void BM_Group_MatchFirstEmptyOrDeleted(benchmark::State& state) { std::array group; Iota(group.begin(), group.end(), -2); Group g{group.data()}; - for (auto _ : state) ::benchmark::DoNotOptimize(*g.MatchEmptyOrDeleted()); + for (auto _ : state) { + ::benchmark::DoNotOptimize(g); + ::benchmark::DoNotOptimize(*g.MatchEmptyOrDeleted()); + } } BENCHMARK(BM_Group_MatchFirstEmptyOrDeleted); diff --git a/absl/debugging/internal/address_is_readable.cc b/absl/debugging/internal/address_is_readable.cc index 26df3289..4be6256b 100644 --- a/absl/debugging/internal/address_is_readable.cc +++ b/absl/debugging/internal/address_is_readable.cc @@ -30,16 +30,12 @@ bool AddressIsReadable(const void* /* addr */) { return true; } ABSL_NAMESPACE_END } // namespace absl -#else +#else // __linux__ && !__ANDROID__ -#include -#include -#include -#include +#include +#include #include -#include - #include "absl/base/internal/errno_saver.h" #include "absl/base/internal/raw_logging.h" @@ -47,60 +43,54 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { +// NOTE: be extra careful about adding any interposable function calls here +// (such as open(), read(), etc.). These symbols may be interposed and will get +// invoked in contexts they don't expect. +// +// NOTE: any new system calls here may also require sandbox reconfiguration. +// bool AddressIsReadable(const void *addr) { - int fd = 0; + // Align address on 8-byte boundary. On aarch64, checking last + // byte before inaccessible page returned unexpected EFAULT. + const uintptr_t u_addr = reinterpret_cast(addr) & ~7; + addr = reinterpret_cast(u_addr); + + // rt_sigprocmask below will succeed for this input. + if (addr == nullptr) return false; + absl::base_internal::ErrnoSaver errno_saver; - for (int j = 0; j < 2; j++) { - // Here we probe with some syscall which - // - accepts a one-byte region of user memory as input - // - tests for EFAULT before other validation - // - has no problematic side-effects - // - // connect(2) works for this. It copies the address into kernel - // memory before any validation beyond requiring an open fd. - // But a one byte address is never valid (sa_family is two bytes), - // so the call cannot succeed and change any state. - // - // This strategy depends on Linux implementation details, - // so we rely on the test to alert us if it stops working. - // - // Some discarded past approaches: - // - msync() doesn't reject PROT_NONE regions - // - write() on /dev/null doesn't return EFAULT - // - write() on a pipe requires creating it and draining the writes - // - // Use syscall(SYS_connect, ...) instead of connect() to prevent ASAN - // and other checkers from complaining about accesses to arbitrary memory. - do { - ABSL_RAW_CHECK(syscall(SYS_connect, fd, addr, 1) == -1, - "should never succeed"); - } while (errno == EINTR); - if (errno == EFAULT) return false; - if (errno == EBADF) { - if (j != 0) { - // Unclear what happened. - ABSL_RAW_LOG(ERROR, "unexpected EBADF on fd %d", fd); - return false; - } - // fd 0 must have been closed. Try opening it again. - // Note: we shouldn't leak too many file descriptors here, since we expect - // to get fd==0 reopened. - fd = open("/dev/null", O_RDONLY); - if (fd == -1) { - ABSL_RAW_LOG(ERROR, "can't open /dev/null"); - return false; - } - } else { - // probably EINVAL or ENOTSOCK; we got past EFAULT validation. - return true; - } - } - ABSL_RAW_CHECK(false, "unreachable"); - return false; + + // Here we probe with some syscall which + // - accepts an 8-byte region of user memory as input + // - tests for EFAULT before other validation + // - has no problematic side-effects + // + // rt_sigprocmask(2) works for this. It copies sizeof(kernel_sigset_t)==8 + // bytes from the address into the kernel memory before any validation. + // + // The call can never succeed, since the `how` parameter is not one of + // SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK. + // + // This strategy depends on Linux implementation details, + // so we rely on the test to alert us if it stops working. + // + // Some discarded past approaches: + // - msync() doesn't reject PROT_NONE regions + // - write() on /dev/null doesn't return EFAULT + // - write() on a pipe requires creating it and draining the writes + // - connect() works but is problematic for sandboxes and needs a valid + // file descriptor + // + // This can never succeed (invalid first argument to sigprocmask). + ABSL_RAW_CHECK(syscall(SYS_rt_sigprocmask, ~0, addr, nullptr, + /*sizeof(kernel_sigset_t)*/ 8) == -1, + "unexpected success"); + ABSL_RAW_CHECK(errno == EFAULT || errno == EINVAL, "unexpected errno"); + return errno != EFAULT; } } // namespace debugging_internal ABSL_NAMESPACE_END } // namespace absl -#endif +#endif // __linux__ && !__ANDROID__ diff --git a/absl/flags/declare.h b/absl/flags/declare.h index b9794d8b..a791b667 100644 --- a/absl/flags/declare.h +++ b/absl/flags/declare.h @@ -60,6 +60,10 @@ ABSL_NAMESPACE_END // The ABSL_DECLARE_FLAG(type, name) macro expands to: // // extern absl::Flag FLAGS_name; -#define ABSL_DECLARE_FLAG(type, name) extern ::absl::Flag FLAGS_##name +#define ABSL_DECLARE_FLAG(type, name) \ + extern absl::Flag FLAGS_##name; \ + namespace absl /* block flags in namespaces */ {} \ + /* second redeclaration is to allow applying attributes */ \ + extern absl::Flag FLAGS_##name #endif // ABSL_FLAGS_DECLARE_H_ diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc index bbe7b965..9bb58fc6 100644 --- a/absl/random/internal/randen_detect.cc +++ b/absl/random/internal/randen_detect.cc @@ -40,7 +40,6 @@ #if defined(ABSL_INTERNAL_USE_X86_CPUID) #if defined(_WIN32) || defined(_WIN64) #include // NOLINT(build/include_order) -#pragma intrinsic(__cpuid) #else // MSVC-equivalent __cpuid intrinsic function. static void __cpuid(int cpu_info[4], int info_type) { diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h index b46bc71f..9b8e5d1a 100644 --- a/absl/strings/ascii.h +++ b/absl/strings/ascii.h @@ -133,7 +133,7 @@ inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; } // ascii_isprint() // -// Determines whether the given character is printable, including whitespace. +// Determines whether the given character is printable, including spaces. inline bool ascii_isprint(unsigned char c) { return c >= 32 && c < 127; } // ascii_isgraph() diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 5905bac0..425b4bee 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -311,11 +311,10 @@ static CordRep* CordRepFromString(std::string&& src) { constexpr unsigned char Cord::InlineRep::kMaxInline; -inline void Cord::InlineRep::set_data(const char* data, size_t n, - bool nullify_tail) { +inline void Cord::InlineRep::set_data(const char* data, size_t n) { static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15"); - cord_internal::SmallMemmove(data_.as_chars(), data, n, nullify_tail); + cord_internal::SmallMemmove(data_.as_chars(), data, n); set_inline_size(n); } @@ -375,7 +374,8 @@ void Cord::InlineRep::AppendTreeToTree(CordRep* tree, MethodIdentifier method) { } void Cord::InlineRep::AppendTree(CordRep* tree, MethodIdentifier method) { - if (tree == nullptr) return; + assert(tree != nullptr); + assert(tree->length != 0); assert(!tree->IsCrc()); if (data_.is_tree()) { AppendTreeToTree(tree, method); @@ -412,6 +412,7 @@ void Cord::InlineRep::PrependTreeToTree(CordRep* tree, void Cord::InlineRep::PrependTree(CordRep* tree, MethodIdentifier method) { assert(tree != nullptr); + assert(tree->length != 0); assert(!tree->IsCrc()); if (data_.is_tree()) { PrependTreeToTree(tree, method); @@ -549,7 +550,7 @@ Cord::Cord(absl::string_view src, MethodIdentifier method) : contents_(InlineData::kDefaultInit) { const size_t n = src.size(); if (n <= InlineRep::kMaxInline) { - contents_.set_data(src.data(), n, true); + contents_.set_data(src.data(), n); } else { CordRep* rep = NewTree(src.data(), n, 0); contents_.EmplaceTree(rep, method); @@ -559,7 +560,7 @@ Cord::Cord(absl::string_view src, MethodIdentifier method) template > Cord::Cord(T&& src) : contents_(InlineData::kDefaultInit) { if (src.size() <= InlineRep::kMaxInline) { - contents_.set_data(src.data(), src.size(), true); + contents_.set_data(src.data(), src.size()); } else { CordRep* rep = CordRepFromString(std::forward(src)); contents_.EmplaceTree(rep, CordzUpdateTracker::kConstructorString); @@ -610,7 +611,7 @@ Cord& Cord::operator=(absl::string_view src) { // - MaybeUntrackCord must be called before set_data() clobbers cordz_info. // - set_data() must be called before Unref(tree) as it may reference tree. if (tree != nullptr) CordzInfo::MaybeUntrackCord(contents_.cordz_info()); - contents_.set_data(data, length, true); + contents_.set_data(data, length); if (tree != nullptr) CordRep::Unref(tree); return *this; } @@ -1014,9 +1015,7 @@ Cord Cord::Subcord(size_t pos, size_t new_size) const { CordRep* tree = contents_.tree(); if (tree == nullptr) { - // sub_cord is newly constructed, no need to re-zero-out the tail of - // contents_ memory. - sub_cord.contents_.set_data(contents_.data() + pos, new_size, false); + sub_cord.contents_.set_data(contents_.data() + pos, new_size); return sub_cord; } diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 27d3475f..3bbd763e 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -763,9 +763,8 @@ class Cord { bool empty() const; size_t size() const; const char* data() const; // Returns nullptr if holding pointer - void set_data(const char* data, size_t n, - bool nullify_tail); // Discards pointer, if any - char* set_data(size_t n); // Write data to the result + void set_data(const char* data, size_t n); // Discards pointer, if any + char* set_data(size_t n); // Write data to the result // Returns nullptr if holding bytes absl::cord_internal::CordRep* tree() const; absl::cord_internal::CordRep* as_tree() const; @@ -857,7 +856,7 @@ class Cord { bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); } // Returns the available inlined capacity, or 0 if is_tree() == true. - size_t inline_capacity() const { + size_t remaining_inline_capacity() const { return data_.is_tree() ? 0 : kMaxInline - data_.inline_size(); } @@ -968,8 +967,8 @@ namespace cord_internal { // Fast implementation of memmove for up to 15 bytes. This implementation is // safe for overlapping regions. If nullify_tail is true, the destination is // padded with '\0' up to 16 bytes. -inline void SmallMemmove(char* dst, const char* src, size_t n, - bool nullify_tail = false) { +template +inline void SmallMemmove(char* dst, const char* src, size_t n) { if (n >= 8) { assert(n <= 16); uint64_t buf1; @@ -1006,22 +1005,16 @@ inline void SmallMemmove(char* dst, const char* src, size_t n, } // Does non-template-specific `CordRepExternal` initialization. -// Expects `data` to be non-empty. +// Requires `data` to be non-empty. void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep); // Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer -// to it, or `nullptr` if `data` was empty. +// to it. Requires `data` to be non-empty. template // NOLINTNEXTLINE - suppress clang-tidy raw pointer return. CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) { + assert(!data.empty()); using ReleaserType = absl::decay_t; - if (data.empty()) { - // Never create empty external nodes. - InvokeReleaser(Rank0{}, ReleaserType(std::forward(releaser)), - data); - return nullptr; - } - CordRepExternal* rep = new CordRepExternalImpl( std::forward(releaser), 0); InitializeCordRepExternal(data, rep); @@ -1041,10 +1034,15 @@ inline CordRep* NewExternalRep(absl::string_view data, template Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) { Cord cord; - if (auto* rep = ::absl::cord_internal::NewExternalRep( - data, std::forward(releaser))) { - cord.contents_.EmplaceTree(rep, + if (ABSL_PREDICT_TRUE(!data.empty())) { + cord.contents_.EmplaceTree(::absl::cord_internal::NewExternalRep( + data, std::forward(releaser)), Cord::MethodIdentifier::kMakeCordFromExternal); + } else { + using ReleaserType = absl::decay_t; + cord_internal::InvokeReleaser( + cord_internal::Rank0{}, ReleaserType(std::forward(releaser)), + data); } return cord; } diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index ea865cca..a22db0bb 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -1370,31 +1370,64 @@ TEST_P(CordTest, ConstructFromExternalNonTrivialReleaserDestructor) { } TEST_P(CordTest, ConstructFromExternalReferenceQualifierOverloads) { - struct Releaser { - void operator()(absl::string_view) & { *lvalue_invoked = true; } - void operator()(absl::string_view) && { *rvalue_invoked = true; } + enum InvokedAs { kMissing, kLValue, kRValue }; + enum CopiedAs { kNone, kMove, kCopy }; + struct Tracker { + CopiedAs copied_as = kNone; + InvokedAs invoked_as = kMissing; + + void Record(InvokedAs rhs) { + ASSERT_EQ(invoked_as, kMissing); + invoked_as = rhs; + } - bool* lvalue_invoked; - bool* rvalue_invoked; - }; + void Record(CopiedAs rhs) { + if (copied_as == kNone || rhs == kCopy) copied_as = rhs; + } + } tracker; - bool lvalue_invoked = false; - bool rvalue_invoked = false; - Releaser releaser = {&lvalue_invoked, &rvalue_invoked}; - (void)MaybeHardened(absl::MakeCordFromExternal("", releaser)); - EXPECT_FALSE(lvalue_invoked); - EXPECT_TRUE(rvalue_invoked); - rvalue_invoked = false; + class Releaser { + public: + explicit Releaser(Tracker* tracker) : tr_(tracker) { *tracker = Tracker(); } + Releaser(Releaser&& rhs) : tr_(rhs.tr_) { tr_->Record(kMove); } + Releaser(const Releaser& rhs) : tr_(rhs.tr_) { tr_->Record(kCopy); } - (void)MaybeHardened(absl::MakeCordFromExternal("dummy", releaser)); - EXPECT_FALSE(lvalue_invoked); - EXPECT_TRUE(rvalue_invoked); - rvalue_invoked = false; - - // NOLINTNEXTLINE: suppress clang-tidy std::move on trivially copyable type. - (void)MaybeHardened(absl::MakeCordFromExternal("dummy", std::move(releaser))); - EXPECT_FALSE(lvalue_invoked); - EXPECT_TRUE(rvalue_invoked); + void operator()(absl::string_view) & { tr_->Record(kLValue); } + void operator()(absl::string_view) && { tr_->Record(kRValue); } + + private: + Tracker* tr_; + }; + + const Releaser releaser1(&tracker); + (void)MaybeHardened(absl::MakeCordFromExternal("", releaser1)); + EXPECT_EQ(tracker.copied_as, kCopy); + EXPECT_EQ(tracker.invoked_as, kRValue); + + const Releaser releaser2(&tracker); + (void)MaybeHardened(absl::MakeCordFromExternal("", releaser2)); + EXPECT_EQ(tracker.copied_as, kCopy); + EXPECT_EQ(tracker.invoked_as, kRValue); + + Releaser releaser3(&tracker); + (void)MaybeHardened(absl::MakeCordFromExternal("", std::move(releaser3))); + EXPECT_EQ(tracker.copied_as, kMove); + EXPECT_EQ(tracker.invoked_as, kRValue); + + Releaser releaser4(&tracker); + (void)MaybeHardened(absl::MakeCordFromExternal("dummy", releaser4)); + EXPECT_EQ(tracker.copied_as, kCopy); + EXPECT_EQ(tracker.invoked_as, kRValue); + + const Releaser releaser5(&tracker); + (void)MaybeHardened(absl::MakeCordFromExternal("dummy", releaser5)); + EXPECT_EQ(tracker.copied_as, kCopy); + EXPECT_EQ(tracker.invoked_as, kRValue); + + Releaser releaser6(&tracker); + (void)MaybeHardened(absl::MakeCordFromExternal("foo", std::move(releaser6))); + EXPECT_EQ(tracker.copied_as, kMove); + EXPECT_EQ(tracker.invoked_as, kRValue); } TEST_P(CordTest, ExternalMemoryBasicUsage) { diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index 151c56f5..dae4e63f 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h @@ -159,8 +159,8 @@ class Arg { Arg(Hex hex); // NOLINT(runtime/explicit) Arg(Dec dec); // NOLINT(runtime/explicit) - // vector::reference and const_reference require special help to - // convert to `AlphaNum` because it requires two user defined conversions. + // vector::reference and const_reference require special help to convert + // to `Arg` because it requires two user defined conversions. template ::value && diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index 76ad41fe..3af4cda9 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -2327,7 +2327,7 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { base_internal::CycleClock::Now() - enqueue_timestamp; mutex_tracer("slow release", this, wait_cycles); ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); - submit_profile_data(enqueue_timestamp); + submit_profile_data(wait_cycles); ABSL_TSAN_MUTEX_POST_DIVERT(this, 0); } } diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h index 9a354ca2..429968da 100644 --- a/absl/synchronization/notification.h +++ b/absl/synchronization/notification.h @@ -22,7 +22,7 @@ // The `Notification` object maintains a private boolean "notified" state that // transitions to `true` at most once. The `Notification` class provides the // following primary member functions: -// * `HasBeenNotified() `to query its state +// * `HasBeenNotified()` to query its state // * `WaitForNotification*()` to have threads wait until the "notified" state // is `true`. // * `Notify()` to set the notification's "notified" state to `true` and -- cgit v1.2.3 From 2a042b082ca6fc8592ec98d800012fc03c965c15 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 10 Jan 2022 10:41:45 -0800 Subject: Export of internal Abseil changes -- 389189dbb322df0d0468ab13edf7dc185dc63833 by Abseil Team : absl str_format.h can compile with -Wconversion and -Wsign-compare PiperOrigin-RevId: 420799960 -- 762e5adc429fc143756c42fe92fe8073c87c075f by Abseil Team : GetStackTraceWithContext: Fix min_dropped_frames when no frames are recorded Previously, if there were still frames to skip, they would be included in min_dropped_frames. PiperOrigin-RevId: 420766341 -- 7d4374b8eaa410f4f98ec03d6a8997dccadfb271 by Abseil Team : absl::flags compiles with -Wconversion and -Wsign-compare PiperOrigin-RevId: 420476807 -- 5f00f7805419d725fa1ff57b388e4c0750d1d6b0 by Derek Mauro : Internal change PiperOrigin-RevId: 420282152 -- bd5471fc34956acf3888bf90287b2aee4415c96d by Derek Mauro : Internal change PiperOrigin-RevId: 420282033 -- 61c78020804e4290e9b2fe151aeaf99b198716ee by Derek Mauro : Internal change PiperOrigin-RevId: 420281867 -- dbe3aad24b65ea11664401a307ea3d2f28e8a7b9 by Derek Mauro : Remove the incorrect test for the availability of [[nodiscard]] It should have been ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) instead of ABSL_HAVE_ATTRIBUTE(nodiscard). As a result, some code is not compliant with [[nodiscard]], so we cannot simply correct the availability test. Recommend that C++17-only code use the standard [[nodiscard] directly. PiperOrigin-RevId: 420150702 GitOrigin-RevId: 389189dbb322df0d0468ab13edf7dc185dc63833 Change-Id: Idf6ebae3c4edd945c9032c7db3d0ab32d16e8078 --- absl/base/attributes.h | 10 +++++++--- absl/debugging/internal/stacktrace_aarch64-inl.inc | 11 ++++++++--- absl/debugging/internal/stacktrace_arm-inl.inc | 11 ++++++++--- absl/debugging/internal/stacktrace_powerpc-inl.inc | 11 ++++++++--- absl/debugging/internal/stacktrace_riscv-inl.inc | 11 ++++++++--- absl/debugging/internal/stacktrace_x86-inl.inc | 11 ++++++++--- absl/flags/internal/flag.h | 8 +++++--- absl/strings/internal/str_format/arg.h | 2 +- absl/strings/internal/str_format/extension.h | 6 ++++-- absl/strings/internal/str_format/output.h | 3 ++- absl/strings/internal/str_format/parser.h | 6 ++++-- 11 files changed, 63 insertions(+), 27 deletions(-) (limited to 'absl/debugging') diff --git a/absl/base/attributes.h b/absl/base/attributes.h index f180cd77..00aad489 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -401,6 +401,9 @@ // // Tells the compiler to warn about unused results. // +// For code or headers that are assured to only build with C++17 and up, prefer +// just using the standard `[[nodiscard]]` directly over this macro. +// // When annotating a function, it must appear as the first part of the // declaration or definition. The compiler will warn if the return value from // such a function is unused: @@ -427,9 +430,10 @@ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 // // Note: past advice was to place the macro after the argument list. -#if ABSL_HAVE_ATTRIBUTE(nodiscard) -#define ABSL_MUST_USE_RESULT [[nodiscard]] -#elif defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result) +// +// TODO(b/176172494): Use ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) when all code is +// compliant with the stricter [[nodiscard]]. +#if defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result) #define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result)) #else #define ABSL_MUST_USE_RESULT diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc index f4859d7c..4f9db9d6 100644 --- a/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc @@ -176,12 +176,17 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, // Implementation detail: we clamp the max of frames we are willing to // count, so as not to spend too much time in the loop below. const int kMaxUnwind = 200; - int j = 0; - for (; frame_pointer != nullptr && j < kMaxUnwind; j++) { + int num_dropped_frames = 0; + for (int j = 0; frame_pointer != nullptr && j < kMaxUnwind; j++) { + if (skip_count > 0) { + skip_count--; + } else { + num_dropped_frames++; + } frame_pointer = NextStackFrame(frame_pointer, ucp); } - *min_dropped_frames = j; + *min_dropped_frames = num_dropped_frames; } return n; } diff --git a/absl/debugging/internal/stacktrace_arm-inl.inc b/absl/debugging/internal/stacktrace_arm-inl.inc index 2a1bf2e8..102a2a12 100644 --- a/absl/debugging/internal/stacktrace_arm-inl.inc +++ b/absl/debugging/internal/stacktrace_arm-inl.inc @@ -112,11 +112,16 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, // Implementation detail: we clamp the max of frames we are willing to // count, so as not to spend too much time in the loop below. const int kMaxUnwind = 200; - int j = 0; - for (; sp != nullptr && j < kMaxUnwind; j++) { + int num_dropped_frames = 0; + for (int j = 0; sp != nullptr && j < kMaxUnwind; j++) { + if (skip_count > 0) { + skip_count--; + } else { + num_dropped_frames++; + } sp = NextStackFrame(sp); } - *min_dropped_frames = j; + *min_dropped_frames = num_dropped_frames; } return n; } diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc index cf8c0516..085cef67 100644 --- a/absl/debugging/internal/stacktrace_powerpc-inl.inc +++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc @@ -231,11 +231,16 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, // Implementation detail: we clamp the max of frames we are willing to // count, so as not to spend too much time in the loop below. const int kMaxUnwind = 1000; - int j = 0; - for (; next_sp != nullptr && j < kMaxUnwind; j++) { + int num_dropped_frames = 0; + for (int j = 0; next_sp != nullptr && j < kMaxUnwind; j++) { + if (skip_count > 0) { + skip_count--; + } else { + num_dropped_frames++; + } next_sp = NextStackFrame(next_sp, ucp); } - *min_dropped_frames = j; + *min_dropped_frames = num_dropped_frames; } return n; } diff --git a/absl/debugging/internal/stacktrace_riscv-inl.inc b/absl/debugging/internal/stacktrace_riscv-inl.inc index 8cbc7854..b4bdb5f1 100644 --- a/absl/debugging/internal/stacktrace_riscv-inl.inc +++ b/absl/debugging/internal/stacktrace_riscv-inl.inc @@ -213,12 +213,17 @@ static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, // Implementation detail: we clamp the max of frames we are willing to // count, so as not to spend too much time in the loop below. const int kMaxUnwind = 200; - int j = 0; - for (; frame_pointer != nullptr && j < kMaxUnwind; j++) { + int num_dropped_frames = 0; + for (int j = 0; frame_pointer != nullptr && j < kMaxUnwind; j++) { + if (skip_count > 0) { + skip_count--; + } else { + num_dropped_frames++; + } frame_pointer = NextStackFrame(frame_pointer, ucp); } - *min_dropped_frames = j; + *min_dropped_frames = num_dropped_frames; } return n; } diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc index 847a5473..1b5d8235 100644 --- a/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/absl/debugging/internal/stacktrace_x86-inl.inc @@ -341,12 +341,17 @@ static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, // Implementation detail: we clamp the max of frames we are willing to // count, so as not to spend too much time in the loop below. const int kMaxUnwind = 1000; - int j = 0; - for (; fp != nullptr && j < kMaxUnwind; j++) { + int num_dropped_frames = 0; + for (int j = 0; fp != nullptr && j < kMaxUnwind; j++) { + if (skip_count > 0) { + skip_count--; + } else { + num_dropped_frames++; + } fp = NextStackFrame(fp, ucp, stack_low, stack_high); } - *min_dropped_frames = j; + *min_dropped_frames = num_dropped_frames; } return n; } diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index 2d0a7e9c..6154638c 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -303,7 +303,9 @@ constexpr FlagDefaultArg DefaultArg(char) { /////////////////////////////////////////////////////////////////////////////// // Flag current value auxiliary structs. -constexpr int64_t UninitializedFlagValue() { return 0xababababababababll; } +constexpr int64_t UninitializedFlagValue() { + return static_cast(0xababababababababll); +} template using FlagUseValueAndInitBitStorage = std::integral_constant< @@ -755,8 +757,8 @@ void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) { case FlagOp::kValueOffset: { // Round sizeof(FlagImp) to a multiple of alignof(FlagValue) to get the // offset of the data. - ptrdiff_t round_to = alignof(FlagValue); - ptrdiff_t offset = + size_t round_to = alignof(FlagValue); + size_t offset = (sizeof(FlagImpl) + round_to - 1) / round_to * round_to; return reinterpret_cast(offset); } diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index 3c91be70..b9dda909 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h @@ -144,7 +144,7 @@ StringConvertResult FormatConvertImpl(const AbslCord& value, size_t space_remaining = 0; int width = conv.width(); - if (width >= 0) space_remaining = width; + if (width >= 0) space_remaining = static_cast(width); size_t to_write = value.size(); diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h index 55cbb56d..c47536d6 100644 --- a/absl/strings/internal/str_format/extension.h +++ b/absl/strings/internal/str_format/extension.h @@ -70,7 +70,7 @@ class FormatSinkImpl { ~FormatSinkImpl() { Flush(); } void Flush() { - raw_.Write(string_view(buf_, pos_ - buf_)); + raw_.Write(string_view(buf_, static_cast(pos_ - buf_))); pos_ = buf_; } @@ -120,7 +120,9 @@ class FormatSinkImpl { } private: - size_t Avail() const { return buf_ + sizeof(buf_) - pos_; } + size_t Avail() const { + return static_cast(buf_ + sizeof(buf_) - pos_); + } FormatRawSinkImpl raw_; size_t size_ = 0; diff --git a/absl/strings/internal/str_format/output.h b/absl/strings/internal/str_format/output.h index 8030dae0..15e751ab 100644 --- a/absl/strings/internal/str_format/output.h +++ b/absl/strings/internal/str_format/output.h @@ -22,6 +22,7 @@ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ #include +#include #include #include @@ -71,7 +72,7 @@ inline void AbslFormatFlush(std::string* out, string_view s) { out->append(s.data(), s.size()); } inline void AbslFormatFlush(std::ostream* out, string_view s) { - out->write(s.data(), s.size()); + out->write(s.data(), static_cast(s.size())); } inline void AbslFormatFlush(FILERawSink* sink, string_view v) { diff --git a/absl/strings/internal/str_format/parser.h b/absl/strings/internal/str_format/parser.h index ad8646ed..32b91d03 100644 --- a/absl/strings/internal/str_format/parser.h +++ b/absl/strings/internal/str_format/parser.h @@ -151,7 +151,8 @@ bool ParseFormatString(string_view src, Consumer consumer) { const char* p = src.data(); const char* const end = p + src.size(); while (p != end) { - const char* percent = static_cast(memchr(p, '%', end - p)); + const char* percent = + static_cast(memchr(p, '%', static_cast(end - p))); if (!percent) { // We found the last substring. return consumer.Append(string_view(p, end - p)); @@ -242,7 +243,8 @@ class ParsedFormatBase { string_view text(base, 0); for (const auto& item : items_) { const char* const end = text.data() + text.size(); - text = string_view(end, (base + item.text_end) - end); + text = + string_view(end, static_cast((base + item.text_end) - end)); if (item.is_conversion) { if (!consumer.ConvertOne(item.conv, text)) return false; } else { -- cgit v1.2.3 From 36db0e4b695756c948dbb45568b43a62ba5883ec Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 3 Feb 2022 08:46:25 -0800 Subject: Export of internal Abseil changes -- 4409b08e103d6e7041d18a4d431290cafe3650cf by Derek Mauro : Workaround NVCC compile error in StringConstant Based on a patch in TensorFlow: https://github.com/tensorflow/tensorflow/blob/da83132aba8d2b6a3c3a9b2e662868eb24f4dd1e/third_party/absl/com_google_absl_fix_mac_and_nvcc_build.patch#L262-L282 Fixes #1105 PiperOrigin-RevId: 426156316 -- 25db16567ffc5400dfaa30b567398ede84729687 by Abseil Team : Only look for Elf64_Auxinfo on 64-bit FreeBSD. PiperOrigin-RevId: 426132251 -- 2e73c3d9df59b2b769d2b8dca97f0ca5c512c72a by Abseil Team : Add a problem hint to the error message when dereferencing the end() iterator. PiperOrigin-RevId: 426120394 -- 6befbf89c47963656b9e8151166ab4c8446d4785 by Martijn Vels : Make Cord Btree the default and remove opt out machinery This change makes btree the default Cord format and removes the machinery to opt out. Subsequent changes will remove the 'true' constant evaluation and effectively cleanup all old code and references to CONCAT. PiperOrigin-RevId: 426119728 -- f6a0a664029d61811d90bd484f4eefa0400b5dd4 by Abseil Team : Mark Notification::HasBeenNotified as ABSL_MUST_USE_RESULT PiperOrigin-RevId: 425927033 GitOrigin-RevId: 4409b08e103d6e7041d18a4d431290cafe3650cf Change-Id: I86f1052c63c13c6486baf4108de2554f162f9c40 --- absl/container/internal/raw_hash_set.h | 16 +++++--- absl/debugging/internal/vdso_support.cc | 2 + absl/strings/cord.cc | 5 +-- absl/strings/cord_test.cc | 73 +-------------------------------- absl/strings/internal/cord_internal.cc | 1 - absl/strings/internal/cord_internal.h | 6 --- absl/strings/internal/string_constant.h | 8 +++- absl/synchronization/notification.h | 3 +- 8 files changed, 24 insertions(+), 90 deletions(-) (limited to 'absl/debugging') diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 93a3fa85..7409d5ec 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -535,15 +535,19 @@ size_t SelectBucketCountForIterRange(InputIter first, InputIter last, } inline void AssertIsFull(ctrl_t* ctrl) { - ABSL_HARDENING_ASSERT((ctrl != nullptr && IsFull(*ctrl)) && - "Invalid operation on iterator. The element might have " - "been erased, or the table might have rehashed."); + ABSL_HARDENING_ASSERT( + (ctrl != nullptr && IsFull(*ctrl)) && + "Invalid operation on iterator. The element might have " + "been erased, the table might have rehashed, or this may " + "be an end() iterator."); } inline void AssertIsValid(ctrl_t* ctrl) { - ABSL_HARDENING_ASSERT((ctrl == nullptr || IsFull(*ctrl)) && - "Invalid operation on iterator. The element might have " - "been erased, or the table might have rehashed."); + ABSL_HARDENING_ASSERT( + (ctrl == nullptr || IsFull(*ctrl)) && + "Invalid operation on iterator. The element might have " + "been erased, the table might have rehashed, or this may " + "be an end() iterator."); } struct FindInfo { diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc index 977a9f6b..8a015d55 100644 --- a/absl/debugging/internal/vdso_support.cc +++ b/absl/debugging/internal/vdso_support.cc @@ -51,7 +51,9 @@ #endif #if defined(__FreeBSD__) +#if defined(__ELF_WORD_SIZE) && __ELF_WORD_SIZE == 64 using Elf64_auxv_t = Elf64_Auxinfo; +#endif using Elf32_auxv_t = Elf32_Auxinfo; #endif diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index ddd14ef4..59722107 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -96,10 +96,7 @@ static constexpr uint64_t min_length[] = { static const int kMinLengthSize = ABSL_ARRAYSIZE(min_length); -static inline bool btree_enabled() { - return cord_internal::cord_btree_enabled.load( - std::memory_order_relaxed); -} +static inline constexpr bool btree_enabled() { return true; } static inline bool IsRootBalanced(CordRep* node) { if (!node->IsConcat()) { diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index e499b55f..c26e506d 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -231,15 +231,7 @@ ABSL_NAMESPACE_END // and with our without expected CRCs being set on the subject Cords. class CordTest : public testing::TestWithParam { public: - CordTest() : was_btree_(absl::cord_internal::cord_btree_enabled.load()) { - absl::cord_internal::cord_btree_enabled.store(UseBtree()); - } - ~CordTest() override { - absl::cord_internal::cord_btree_enabled.store(was_btree_); - } - // Returns true if test is running with btree enabled. - bool UseBtree() const { return GetParam() == 1 || GetParam() == 3; } bool UseCrc() const { return GetParam() == 2 || GetParam() == 3; } void MaybeHarden(absl::Cord& c) { if (UseCrc()) { @@ -255,27 +247,19 @@ class CordTest : public testing::TestWithParam { static std::string ToString(testing::TestParamInfo param) { switch (param.param) { case 0: - return "Concat"; - case 1: return "Btree"; - case 2: - return "ConcatHardened"; - case 3: + case 1: return "BtreeHardened"; default: assert(false); return "???"; } } - - private: - const bool was_btree_; }; -INSTANTIATE_TEST_SUITE_P(WithParam, CordTest, testing::Values(0, 1, 2, 3), +INSTANTIATE_TEST_SUITE_P(WithParam, CordTest, testing::Values(0, 1), CordTest::ToString); - TEST(CordRepFlat, AllFlatCapacities) { // Explicitly and redundantly assert built-in min/max limits static_assert(absl::cord_internal::kFlatOverhead < 32, ""); @@ -1561,8 +1545,6 @@ TEST(CordTest, CordMemoryUsageFlatHardenedAndShared) { } TEST(CordTest, CordMemoryUsageBTree) { - absl::cord_internal::enable_cord_btree(true); - absl::Cord cord1; size_t flats1_size = 0; absl::Cord flats1[4] = {MakeCord(1000, 'a'), MakeCord(1100, 'a'), @@ -1611,57 +1593,6 @@ TEST(CordTest, CordMemoryUsageBTree) { rep2_size); } -TEST(CordTest, CordMemoryUsageConcat) { - absl::cord_internal::enable_cord_btree(false); - - absl::Cord cord1; - size_t flats1_size = 0; - absl::Cord flats1[4] = {MakeCord(1000, 'a'), MakeCord(1100, 'a'), - MakeCord(1200, 'a'), MakeCord(1300, 'a')}; - for (absl::Cord flat : flats1) { - flats1_size += absl::CordTestPeer::Tree(flat)->flat()->AllocatedSize(); - cord1.Append(std::move(flat)); - } - - // Make sure the created cord is a CONCAT tree. Under some builds such as - // windows DLL, we may have ODR like effects on the flag, meaning the DLL - // code will run with the picked up default. - if (!absl::CordTestPeer::Tree(cord1)->IsConcat()) { - ABSL_RAW_LOG(WARNING, "Cord library code not respecting btree flag"); - return; - } - - size_t rep1_size = sizeof(CordRepConcat) * 3 + flats1_size; - size_t rep1_shared_size = sizeof(CordRepConcat) * 3 + flats1_size / 2; - - EXPECT_EQ(cord1.EstimatedMemoryUsage(), sizeof(absl::Cord) + rep1_size); - EXPECT_EQ(cord1.EstimatedMemoryUsage(kFairShare), - sizeof(absl::Cord) + rep1_shared_size); - - absl::Cord cord2; - size_t flats2_size = 0; - absl::Cord flats2[4] = {MakeCord(600, 'a'), MakeCord(700, 'a'), - MakeCord(800, 'a'), MakeCord(900, 'a')}; - for (absl::Cord& flat : flats2) { - flats2_size += absl::CordTestPeer::Tree(flat)->flat()->AllocatedSize(); - cord2.Append(std::move(flat)); - } - - size_t rep2_size = sizeof(CordRepConcat) * 3 + flats2_size; - - EXPECT_EQ(cord2.EstimatedMemoryUsage(), sizeof(absl::Cord) + rep2_size); - EXPECT_EQ(cord2.EstimatedMemoryUsage(kFairShare), - sizeof(absl::Cord) + rep2_size); - - absl::Cord cord(cord1); - cord.Append(std::move(cord2)); - EXPECT_EQ(cord.EstimatedMemoryUsage(), - sizeof(absl::Cord) + sizeof(CordRepConcat) + rep1_size + rep2_size); - EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare), - sizeof(absl::Cord) + sizeof(CordRepConcat) + rep1_shared_size / 2 + - rep2_size); -} - // Regtest for a change that had to be rolled back because it expanded out // of the InlineRep too soon, which was observable through MemoryUsage(). TEST_P(CordTest, CordMemoryUsageInlineRep) { diff --git a/absl/strings/internal/cord_internal.cc b/absl/strings/internal/cord_internal.cc index c9ceac90..feb3bec1 100644 --- a/absl/strings/internal/cord_internal.cc +++ b/absl/strings/internal/cord_internal.cc @@ -27,7 +27,6 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { -ABSL_CONST_INIT std::atomic cord_btree_enabled(kCordEnableBtreeDefault); ABSL_CONST_INIT std::atomic cord_ring_buffer_enabled( kCordEnableRingBufferDefault); ABSL_CONST_INIT std::atomic shallow_subcords_enabled( diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h index 776d1c40..b9ecbba6 100644 --- a/absl/strings/internal/cord_internal.h +++ b/absl/strings/internal/cord_internal.h @@ -37,12 +37,10 @@ class CordzInfo; // Default feature enable states for cord ring buffers enum CordFeatureDefaults { - kCordEnableBtreeDefault = true, kCordEnableRingBufferDefault = false, kCordShallowSubcordsDefault = false }; -extern std::atomic cord_btree_enabled; extern std::atomic cord_ring_buffer_enabled; extern std::atomic shallow_subcords_enabled; @@ -52,10 +50,6 @@ extern std::atomic shallow_subcords_enabled; // O(n^2) complexity as recursive / full tree validation is O(n). extern std::atomic cord_btree_exhaustive_validation; -inline void enable_cord_btree(bool enable) { - cord_btree_enabled.store(enable, std::memory_order_relaxed); -} - inline void enable_cord_ring_buffer(bool enable) { cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed); } diff --git a/absl/strings/internal/string_constant.h b/absl/strings/internal/string_constant.h index a11336b7..b358efdd 100644 --- a/absl/strings/internal/string_constant.h +++ b/absl/strings/internal/string_constant.h @@ -35,12 +35,18 @@ namespace strings_internal { // below. template struct StringConstant { + private: + static constexpr bool TryConstexprEval(absl::string_view view) { + return view.empty() || 2 * view[0] != 1; + } + + public: static constexpr absl::string_view value = T{}(); constexpr absl::string_view operator()() const { return value; } // Check to be sure `view` points to constant data. // Otherwise, it can't be constant evaluated. - static_assert(value.empty() || 2 * value[0] != 1, + static_assert(TryConstexprEval(value), "The input string_view must point to constant data."); }; diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h index 429968da..4bec2689 100644 --- a/absl/synchronization/notification.h +++ b/absl/synchronization/notification.h @@ -52,6 +52,7 @@ #include +#include "absl/base/attributes.h" #include "absl/base/macros.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" @@ -74,7 +75,7 @@ class Notification { // Notification::HasBeenNotified() // // Returns the value of the notification's internal "notified" state. - bool HasBeenNotified() const { + ABSL_MUST_USE_RESULT bool HasBeenNotified() const { return HasBeenNotifiedInternal(&this->notified_yet_); } -- cgit v1.2.3 From 7f850b3167fb38e6b4a9ce1824e6fabd733b5d62 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 17 Feb 2022 12:07:55 -0800 Subject: Export of internal Abseil changes -- ed829ac612f090375427c3488827c6e74deb2e3f by Derek Mauro : Update latest GCC/Clang Linux tests to Bazel 5.0.0 and CMake 3.22.2 PiperOrigin-RevId: 429369775 -- 76952303c4d942288c4e7657ffb5893cec54a132 by Martijn Vels : Optimize Cord::ChunkIterator now that CordRepConcat is removed PiperOrigin-RevId: 429321455 -- dcd0d287793649aba9b98268c5783e449a34749f by Martijn Vels : Add IsDataEdge() and DataEdgeValue() helper functions. This moves repetitive logic accessing data edges into its own header, and more strongly defines the notion of what a data edge is, enforcing the internal invariants. This will also be incorporated in optimized Cord iteration logic once CordRepConcat is totally removed from the Cord code. PiperOrigin-RevId: 429307248 -- 6a0903962155988085bf8656743fda9c4cdcba6c by Abseil Team : Make it clear that the probability function given for the zipf distribution is unnormalized, i.e., sum(p(x) for x = 0..k) != 100%. Quoting Section 7 of the paper cited in the comments, where this formula comes from (emphasis mine): "We will consider the two parameter generalization as defined in Dagpunar [1988] with the *unnormalized* probability function ..." PiperOrigin-RevId: 429068258 -- 3899ff6d444ba755148bc521a6ee031d9e9d4485 by Abseil Team : Internal Changes PiperOrigin-RevId: 428644856 -- 319de702d2b537cbb76c4c71277ae89b349b162e by Benjamin Barenblat : Support symbolization on PA-RISC Null out supervisor bits in PA-RISC addresses before symbolizing, and handle function descriptor tables correctly. Change symbolize_test.cc to use 32-bit aligned addresses, allowing that test to pass on PA-RISC. PiperOrigin-RevId: 428590564 GitOrigin-RevId: ed829ac612f090375427c3488827c6e74deb2e3f Change-Id: Ie01ff3b9365fd45e5a55f858038552679f3180d3 --- CMake/AbseilDll.cmake | 1 + absl/debugging/symbolize_elf.inc | 45 +++++- absl/debugging/symbolize_test.cc | 8 +- absl/random/zipf_distribution.h | 2 +- absl/strings/BUILD.bazel | 16 ++ absl/strings/CMakeLists.txt | 18 +++ absl/strings/cord.cc | 173 +++------------------- absl/strings/cord.h | 56 +++---- absl/strings/cord_analysis.cc | 14 +- absl/strings/cord_test.cc | 72 +++++++++ absl/strings/internal/cord_data_edge.h | 63 ++++++++ absl/strings/internal/cord_data_edge_test.cc | 130 ++++++++++++++++ absl/strings/internal/cord_rep_btree.cc | 7 +- absl/strings/internal/cord_rep_btree.h | 31 +--- absl/strings/internal/cord_rep_btree_navigator.cc | 3 +- absl/strings/internal/cord_rep_btree_reader.cc | 5 +- absl/strings/internal/cord_rep_btree_reader.h | 9 +- absl/strings/internal/cord_rep_btree_test.cc | 33 ++--- ci/linux_docker_containers.sh | 4 +- 19 files changed, 427 insertions(+), 263 deletions(-) create mode 100644 absl/strings/internal/cord_data_edge.h create mode 100644 absl/strings/internal/cord_data_edge_test.cc (limited to 'absl/debugging') diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 14ce9d18..0becc7a9 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -204,6 +204,7 @@ set(ABSL_INTERNAL_DLL_FILES "strings/internal/charconv_bigint.h" "strings/internal/charconv_parse.cc" "strings/internal/charconv_parse.h" + "strings/internal/cord_data_edge.h" "strings/internal/cord_internal.cc" "strings/internal/cord_internal.h" "strings/internal/cord_rep_btree.cc" diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index 3ff343d6..ddccd590 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc @@ -323,6 +323,7 @@ class Symbolizer { const ptrdiff_t relocation, char *out, int out_size, char *tmp_buf, int tmp_buf_size); + const char *GetUncachedSymbol(const void *pc); enum { SYMBOL_BUF_SIZE = 3072, @@ -1333,13 +1334,7 @@ static bool MaybeInitializeObjFile(ObjFile *obj) { // they are called here as well. // To keep stack consumption low, we would like this function to not // get inlined. -const char *Symbolizer::GetSymbol(const void *const pc) { - const char *entry = FindSymbolInCache(pc); - if (entry != nullptr) { - return entry; - } - symbol_buf_[0] = '\0'; - +const char *Symbolizer::GetUncachedSymbol(const void *pc) { ObjFile *const obj = FindObjFile(pc, 1); ptrdiff_t relocation = 0; int fd = -1; @@ -1427,6 +1422,42 @@ const char *Symbolizer::GetSymbol(const void *const pc) { return InsertSymbolInCache(pc, symbol_buf_); } +const char *Symbolizer::GetSymbol(const void *pc) { + const char *entry = FindSymbolInCache(pc); + if (entry != nullptr) { + return entry; + } + symbol_buf_[0] = '\0'; + +#ifdef __hppa__ + { + // In some contexts (e.g., return addresses), PA-RISC uses the lowest two + // bits of the address to indicate the privilege level. Clear those bits + // before trying to symbolize. + const auto pc_bits = reinterpret_cast(pc); + const auto address = pc_bits & ~0x3; + entry = GetUncachedSymbol(reinterpret_cast(address)); + if (entry != nullptr) { + return entry; + } + + // In some contexts, PA-RISC also uses bit 1 of the address to indicate that + // this is a cross-DSO function pointer. Such function pointers actually + // point to a procedure label, a struct whose first 32-bit (pointer) element + // actually points to the function text. With no symbol found for this + // address so far, try interpreting it as a cross-DSO function pointer and + // see how that goes. + if (pc_bits & 0x2) { + return GetUncachedSymbol(*reinterpret_cast(address)); + } + + return nullptr; + } +#else + return GetUncachedSymbol(pc); +#endif +} + bool RemoveAllSymbolDecorators(void) { if (!g_decorators_mu.TryLock()) { // Someone else is using decorators. Get out. diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index c710a3da..a62fa35d 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -392,12 +392,14 @@ TEST(Symbolize, InstallAndRemoveSymbolDecorators) { DummySymbolDecorator, &c_message), 0); - char *address = reinterpret_cast(1); - EXPECT_STREQ("abc", TrySymbolize(address++)); + // Use addresses 4 and 8 here to ensure that we always use valid addresses + // even on systems that require instructions to be 32-bit aligned. + char *address = reinterpret_cast(4); + EXPECT_STREQ("abc", TrySymbolize(address)); EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_b)); - EXPECT_STREQ("ac", TrySymbolize(address++)); + EXPECT_STREQ("ac", TrySymbolize(address + 4)); // Cleanup: remove all remaining decorators so other stack traces don't // get mystery "ac" decoration. diff --git a/absl/random/zipf_distribution.h b/absl/random/zipf_distribution.h index ed4038f1..03497b1b 100644 --- a/absl/random/zipf_distribution.h +++ b/absl/random/zipf_distribution.h @@ -30,7 +30,7 @@ namespace absl { ABSL_NAMESPACE_BEGIN // absl::zipf_distribution produces random integer-values in the range [0, k], -// distributed according to the discrete probability function: +// distributed according to the unnormalized discrete probability function: // // P(x) = (v + x) ^ -q // diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 129affec..5f122ee9 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -276,6 +276,7 @@ cc_library( "internal/cord_rep_ring.cc", ], hdrs = [ + "internal/cord_data_edge.h", "internal/cord_internal.h", "internal/cord_rep_btree.h", "internal/cord_rep_btree_navigator.h", @@ -307,6 +308,21 @@ cc_library( ], ) +cc_test( + name = "cord_data_edge_test", + size = "small", + srcs = ["internal/cord_data_edge_test.cc"], + copts = ABSL_TEST_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":cord_internal", + ":cord_rep_test_util", + ":strings", + "//absl/base:config", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "cord_rep_btree_test", size = "medium", diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index f31eef4d..5d418c86 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -554,6 +554,7 @@ absl_cc_library( NAME cord_internal HDRS + "internal/cord_data_edge.h" "internal/cord_internal.h" "internal/cord_rep_btree.h" "internal/cord_rep_btree_navigator.h" @@ -932,6 +933,23 @@ absl_cc_test( GTest::gmock_main ) +absl_cc_test( + NAME + cord_data_edge_test + SRCS + "internal/cord_data_edge_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::config + absl::cord_internal + absl::cord_rep_test_util + absl::core_headers + absl::strings + GTest::gmock_main +) + absl_cc_test( NAME cord_rep_btree_test diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 4ee722da..6547c2da 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -35,6 +35,7 @@ #include "absl/container/fixed_array.h" #include "absl/container/inlined_vector.h" #include "absl/strings/escaping.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" @@ -1094,35 +1095,6 @@ void Cord::CopyToArraySlowPath(char* dst) const { } } -Cord::ChunkIterator& Cord::ChunkIterator::AdvanceStack() { - auto& stack_of_right_children = stack_of_right_children_; - if (stack_of_right_children.empty()) { - assert(!current_chunk_.empty()); // Called on invalid iterator. - // We have reached the end of the Cord. - return *this; - } - - // Process the next node on the stack. - CordRep* node = stack_of_right_children.back(); - stack_of_right_children.pop_back(); - - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; - if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } - - assert(node->IsExternal() || node->IsFlat()); - assert(length != 0); - const char* data = - node->IsExternal() ? node->external()->base : node->flat()->Data(); - current_chunk_ = absl::string_view(data + offset, length); - current_leaf_ = node; - return *this; -} - Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { ABSL_HARDENING_ASSERT(bytes_remaining_ >= n && "Attempted to iterate past `end()`"); @@ -1165,133 +1137,36 @@ Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { return subcord; } - auto& stack_of_right_children = stack_of_right_children_; - if (n < current_chunk_.size()) { - // Range to read is a proper subrange of the current chunk. - assert(current_leaf_ != nullptr); - CordRep* subnode = CordRep::Ref(current_leaf_); - const char* data = subnode->IsExternal() ? subnode->external()->base - : subnode->flat()->Data(); - subnode = NewSubstring(subnode, current_chunk_.data() - data, n); - subcord.contents_.EmplaceTree(VerifyTree(subnode), method); - RemoveChunkPrefix(n); - return subcord; - } - - // Range to read begins with a proper subrange of the current chunk. - assert(!current_chunk_.empty()); + // Short circuit if reading the entire data edge. assert(current_leaf_ != nullptr); - CordRep* subnode = CordRep::Ref(current_leaf_); - if (current_chunk_.size() < subnode->length) { - const char* data = subnode->IsExternal() ? subnode->external()->base - : subnode->flat()->Data(); - subnode = NewSubstring(subnode, current_chunk_.data() - data, - current_chunk_.size()); - } - n -= current_chunk_.size(); - bytes_remaining_ -= current_chunk_.size(); - - // Process the next node(s) on the stack, reading whole subtrees depending on - // their length and how many bytes we are advancing. - CordRep* node = nullptr; - while (!stack_of_right_children.empty()) { - node = stack_of_right_children.back(); - stack_of_right_children.pop_back(); - if (node->length > n) break; - // TODO(qrczak): This might unnecessarily recreate existing concat nodes. - // Avoiding that would need pretty complicated logic (instead of - // current_leaf, keep current_subtree_ which points to the highest node - // such that the current leaf can be found on the path of left children - // starting from current_subtree_; delay creating subnode while node is - // below current_subtree_; find the proper node along the path of left - // children starting from current_subtree_ if this loop exits while staying - // below current_subtree_; etc.; alternatively, push parents instead of - // right children on the stack). - subnode = Concat(subnode, CordRep::Ref(node)); - n -= node->length; - bytes_remaining_ -= node->length; - node = nullptr; - } - - if (node == nullptr) { - // We have reached the end of the Cord. - assert(bytes_remaining_ == 0); - subcord.contents_.EmplaceTree(VerifyTree(subnode), method); + if (n == current_leaf_->length) { + bytes_remaining_ = 0; + current_chunk_ = {}; + CordRep* tree = CordRep::Ref(current_leaf_); + subcord.contents_.EmplaceTree(VerifyTree(tree), method); return subcord; } - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; - if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } - - // Range to read ends with a proper (possibly empty) subrange of the current - // chunk. - assert(node->IsExternal() || node->IsFlat()); - assert(length > n); - if (n > 0) { - subnode = Concat(subnode, NewSubstring(CordRep::Ref(node), offset, n)); - } - const char* data = - node->IsExternal() ? node->external()->base : node->flat()->Data(); - current_chunk_ = absl::string_view(data + offset + n, length - n); - current_leaf_ = node; - bytes_remaining_ -= n; - subcord.contents_.EmplaceTree(VerifyTree(subnode), method); - return subcord; -} - -void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) { - assert(bytes_remaining_ >= n && "Attempted to iterate past `end()`"); - assert(n >= current_chunk_.size()); // This should only be called when - // iterating to a new node. - - n -= current_chunk_.size(); - bytes_remaining_ -= current_chunk_.size(); - - if (stack_of_right_children_.empty()) { - // We have reached the end of the Cord. - assert(bytes_remaining_ == 0); - return; - } - - // Process the next node(s) on the stack, skipping whole subtrees depending on - // their length and how many bytes we are advancing. - CordRep* node = nullptr; - auto& stack_of_right_children = stack_of_right_children_; - while (!stack_of_right_children.empty()) { - node = stack_of_right_children.back(); - stack_of_right_children.pop_back(); - if (node->length > n) break; - n -= node->length; - bytes_remaining_ -= node->length; - node = nullptr; - } - - if (node == nullptr) { - // We have reached the end of the Cord. - assert(bytes_remaining_ == 0); - return; - } + // From this point on, we need a partial substring node. + // Get pointer to the underlying flat or external data payload and + // compute data pointer and offset into current flat or external. + CordRep* payload = current_leaf_->IsSubstring() + ? current_leaf_->substring()->child + : current_leaf_; + const char* data = payload->IsExternal() ? payload->external()->base + : payload->flat()->Data(); + const size_t offset = current_chunk_.data() - data; - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; - if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } + CordRepSubstring* tree = new CordRepSubstring(); + tree->tag = cord_internal::SUBSTRING; + tree->length = n; + tree->start = offset; + tree->child = CordRep::Ref(payload); - assert(node->IsExternal() || node->IsFlat()); - assert(length > n); - const char* data = - node->IsExternal() ? node->external()->base : node->flat()->Data(); - current_chunk_ = absl::string_view(data + offset + n, length - n); - current_leaf_ = node; + subcord.contents_.EmplaceTree(VerifyTree(tree), method); bytes_remaining_ -= n; + current_chunk_.remove_prefix(n); + return subcord; } char Cord::operator[](size_t i) const { diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 7f34ef48..081b6311 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -80,6 +80,7 @@ #include "absl/functional/function_ref.h" #include "absl/meta/type_traits.h" #include "absl/strings/cord_analysis.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree_reader.h" @@ -388,12 +389,6 @@ class Cord { using CordRepBtree = absl::cord_internal::CordRepBtree; using CordRepBtreeReader = absl::cord_internal::CordRepBtreeReader; - // Stack of right children of concat nodes that we have to visit. - // Keep this at the end of the structure to avoid cache-thrashing. - // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for - // the inlined vector size (47 exists for backward compatibility). - using Stack = absl::InlinedVector; - // Constructs a `begin()` iterator from `tree`. `tree` must not be null. explicit ChunkIterator(cord_internal::CordRep* tree); @@ -409,17 +404,10 @@ class Cord { Cord AdvanceAndReadBytes(size_t n); void AdvanceBytes(size_t n); - // Stack specific operator++ - ChunkIterator& AdvanceStack(); - // Btree specific operator++ ChunkIterator& AdvanceBtree(); void AdvanceBytesBtree(size_t n); - // Iterates `n` bytes, where `n` is expected to be greater than or equal to - // `current_chunk_.size()`. - void AdvanceBytesSlowPath(size_t n); - // A view into bytes of the current `CordRep`. It may only be a view to a // suffix of bytes if this is being used by `CharIterator`. absl::string_view current_chunk_; @@ -432,9 +420,6 @@ class Cord { // Cord reader for cord btrees. Empty if not traversing a btree. CordRepBtreeReader btree_reader_; - - // See 'Stack' alias definition. - Stack stack_of_right_children_; }; // Cord::ChunkIterator::chunk_begin() @@ -725,7 +710,8 @@ class Cord { // be used by spelling absl::strings_internal::MakeStringConstant, which is // also an internal API. template - explicit constexpr Cord(strings_internal::StringConstant); + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr Cord(strings_internal::StringConstant); private: using CordRep = absl::cord_internal::CordRep; @@ -1321,25 +1307,24 @@ inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) { tree = cord_internal::SkipCrcNode(tree); if (tree->tag == cord_internal::BTREE) { current_chunk_ = btree_reader_.Init(tree->btree()); - return; + } else { + current_leaf_ = tree; + current_chunk_ = cord_internal::EdgeData(tree); } - - stack_of_right_children_.push_back(tree); - operator++(); } -inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) - : bytes_remaining_(tree->length) { +inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) { + bytes_remaining_ = tree->length; InitTree(tree); } -inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) - : bytes_remaining_(cord->size()) { - if (cord->contents_.is_tree()) { - InitTree(cord->contents_.as_tree()); +inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) { + if (CordRep* tree = cord->contents_.tree()) { + bytes_remaining_ = tree->length; + InitTree(tree); } else { - current_chunk_ = - absl::string_view(cord->contents_.data(), bytes_remaining_); + bytes_remaining_ = cord->contents_.inline_size(); + current_chunk_ = {cord->contents_.data(), bytes_remaining_}; } } @@ -1369,8 +1354,11 @@ inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() { assert(bytes_remaining_ >= current_chunk_.size()); bytes_remaining_ -= current_chunk_.size(); if (bytes_remaining_ > 0) { - return btree_reader_ ? AdvanceBtree() : AdvanceStack(); - } else { + if (btree_reader_) { + return AdvanceBtree(); + } else { + assert(!current_chunk_.empty()); // Called on invalid iterator. + } current_chunk_ = {}; } return *this; @@ -1411,7 +1399,11 @@ inline void Cord::ChunkIterator::AdvanceBytes(size_t n) { if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) { RemoveChunkPrefix(n); } else if (n != 0) { - btree_reader_ ? AdvanceBytesBtree(n) : AdvanceBytesSlowPath(n); + if (btree_reader_) { + AdvanceBytesBtree(n); + } else { + bytes_remaining_ = 0; + } } } diff --git a/absl/strings/cord_analysis.cc b/absl/strings/cord_analysis.cc index 3fa15b01..73d3c4e6 100644 --- a/absl/strings/cord_analysis.cc +++ b/absl/strings/cord_analysis.cc @@ -12,13 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "absl/strings/cord_analysis.h" + #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/container/inlined_vector.h" -#include "absl/strings/cord_analysis.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" @@ -98,16 +100,6 @@ struct RawUsage { } }; -// Returns true if the provided rep is a valid data edge. -bool IsDataEdge(const CordRep* rep) { - // The fast path is that `rep` is an EXTERNAL or FLAT node, making the below - // if a single, well predicted branch. We then repeat the FLAT or EXTERNAL - // check in the slow path the SUBSTRING check to optimize for the hot path. - if (rep->tag == EXTERNAL || rep->tag >= FLAT) return true; - if (rep->tag == SUBSTRING) rep = rep->substring()->child; - return rep->tag == EXTERNAL || rep->tag >= FLAT; -} - // Computes the estimated memory size of the provided data edge. // External reps are assumed 'heap allocated at their exact size'. template diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index c26e506d..9dcc4ce5 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -1866,6 +1866,78 @@ TEST_P(CordTest, CordChunkIteratorOperations) { VerifyChunkIterator(subcords, 128); } + +TEST_P(CordTest, AdvanceAndReadOnDataEdge) { + RandomEngine rng(GTEST_FLAG_GET(random_seed)); + const std::string data = RandomLowercaseString(&rng, 2000); + for (bool as_flat : {true, false}) { + SCOPED_TRACE(as_flat ? "Flat" : "External"); + + absl::Cord cord = + as_flat ? absl::Cord(data) + : absl::MakeCordFromExternal(data, [](absl::string_view) {}); + auto it = cord.Chars().begin(); +#if !defined(NDEBUG) || ABSL_OPTION_HARDENED + EXPECT_DEATH_IF_SUPPORTED(cord.AdvanceAndRead(&it, 2001), ".*"); +#endif + + it = cord.Chars().begin(); + absl::Cord frag = cord.AdvanceAndRead(&it, 2000); + EXPECT_EQ(frag, data); + EXPECT_TRUE(it == cord.Chars().end()); + + it = cord.Chars().begin(); + frag = cord.AdvanceAndRead(&it, 200); + EXPECT_EQ(frag, data.substr(0, 200)); + EXPECT_FALSE(it == cord.Chars().end()); + + frag = cord.AdvanceAndRead(&it, 1500); + EXPECT_EQ(frag, data.substr(200, 1500)); + EXPECT_FALSE(it == cord.Chars().end()); + + frag = cord.AdvanceAndRead(&it, 300); + EXPECT_EQ(frag, data.substr(1700, 300)); + EXPECT_TRUE(it == cord.Chars().end()); + } +} + +TEST_P(CordTest, AdvanceAndReadOnSubstringDataEdge) { + RandomEngine rng(GTEST_FLAG_GET(random_seed)); + const std::string data = RandomLowercaseString(&rng, 2500); + for (bool as_flat : {true, false}) { + SCOPED_TRACE(as_flat ? "Flat" : "External"); + + absl::Cord cord = + as_flat ? absl::Cord(data) + : absl::MakeCordFromExternal(data, [](absl::string_view) {}); + cord = cord.Subcord(200, 2000); + const std::string substr = data.substr(200, 2000); + + auto it = cord.Chars().begin(); +#if !defined(NDEBUG) || ABSL_OPTION_HARDENED + EXPECT_DEATH_IF_SUPPORTED(cord.AdvanceAndRead(&it, 2001), ".*"); +#endif + + it = cord.Chars().begin(); + absl::Cord frag = cord.AdvanceAndRead(&it, 2000); + EXPECT_EQ(frag, substr); + EXPECT_TRUE(it == cord.Chars().end()); + + it = cord.Chars().begin(); + frag = cord.AdvanceAndRead(&it, 200); + EXPECT_EQ(frag, substr.substr(0, 200)); + EXPECT_FALSE(it == cord.Chars().end()); + + frag = cord.AdvanceAndRead(&it, 1500); + EXPECT_EQ(frag, substr.substr(200, 1500)); + EXPECT_FALSE(it == cord.Chars().end()); + + frag = cord.AdvanceAndRead(&it, 300); + EXPECT_EQ(frag, substr.substr(1700, 300)); + EXPECT_TRUE(it == cord.Chars().end()); + } +} + TEST_P(CordTest, CharIteratorTraits) { static_assert(std::is_copy_constructible::value, ""); diff --git a/absl/strings/internal/cord_data_edge.h b/absl/strings/internal/cord_data_edge.h new file mode 100644 index 00000000..e18b33e1 --- /dev/null +++ b/absl/strings/internal/cord_data_edge.h @@ -0,0 +1,63 @@ +// Copyright 2022 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_INTERNAL_CORD_DATA_EDGE_H_ +#define ABSL_STRINGS_INTERNAL_CORD_DATA_EDGE_H_ + +#include +#include + +#include "absl/base/config.h" +#include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cord_rep_flat.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + +// Returns true if the provided rep is a FLAT, EXTERNAL or a SUBSTRING node +// holding a FLAT or EXTERNAL child rep. Requires `rep != nullptr`. +inline bool IsDataEdge(const CordRep* edge) { + assert(edge != nullptr); + + // The fast path is that `edge` is an EXTERNAL or FLAT node, making the below + // if a single, well predicted branch. We then repeat the FLAT or EXTERNAL + // check in the slow path of the SUBSTRING check to optimize for the hot path. + if (edge->tag == EXTERNAL || edge->tag >= FLAT) return true; + if (edge->tag == SUBSTRING) edge = edge->substring()->child; + return edge->tag == EXTERNAL || edge->tag >= FLAT; +} + +// Returns the `absl::string_view` data reference for the provided data edge. +// Requires 'IsDataEdge(edge) == true`. +inline absl::string_view EdgeData(const CordRep* edge) { + assert(IsDataEdge(edge)); + + size_t offset = 0; + const size_t length = edge->length; + if (edge->IsSubstring()) { + offset = edge->substring()->start; + edge = edge->substring()->child; + } + return edge->tag >= FLAT + ? absl::string_view{edge->flat()->Data() + offset, length} + : absl::string_view{edge->external()->base + offset, length}; +} + +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_STRINGS_INTERNAL_CORD_DATA_EDGE_H_ diff --git a/absl/strings/internal/cord_data_edge_test.cc b/absl/strings/internal/cord_data_edge_test.cc new file mode 100644 index 00000000..8fce3bc6 --- /dev/null +++ b/absl/strings/internal/cord_data_edge_test.cc @@ -0,0 +1,130 @@ +// Copyright 2022 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/strings/internal/cord_data_edge.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cord_rep_test_util.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { +namespace { + +using ::absl::cordrep_testing::MakeExternal; +using ::absl::cordrep_testing::MakeFlat; +using ::absl::cordrep_testing::MakeSubstring; + +TEST(CordDataEdgeTest, IsDataEdgeOnFlat) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + EXPECT_TRUE(IsDataEdge(rep)); + CordRep::Unref(rep); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnExternal) { + CordRep* rep = MakeExternal("Lorem ipsum dolor sit amet, consectetur ..."); + EXPECT_TRUE(IsDataEdge(rep)); + CordRep::Unref(rep); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnSubstringOfFlat) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRep* substr = MakeSubstring(1, 20, rep); + EXPECT_TRUE(IsDataEdge(substr)); + CordRep::Unref(substr); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnSubstringOfExternal) { + CordRep* rep = MakeExternal("Lorem ipsum dolor sit amet, consectetur ..."); + CordRep* substr = MakeSubstring(1, 20, rep); + EXPECT_TRUE(IsDataEdge(substr)); + CordRep::Unref(substr); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnBtree) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRepBtree* tree = CordRepBtree::New(rep); + EXPECT_FALSE(IsDataEdge(tree)); + CordRep::Unref(tree); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnBadSubstr) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRep* substr = MakeSubstring(1, 18, MakeSubstring(1, 20, rep)); + EXPECT_FALSE(IsDataEdge(substr)); + CordRep::Unref(substr); +} + +TEST(CordDataEdgeTest, EdgeDataOnFlat) { + absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ..."; + CordRep* rep = MakeFlat(value); + EXPECT_EQ(EdgeData(rep), value); + CordRep::Unref(rep); +} + +TEST(CordDataEdgeTest, EdgeDataOnExternal) { + absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ..."; + CordRep* rep = MakeExternal(value); + EXPECT_EQ(EdgeData(rep), value); + CordRep::Unref(rep); +} + +TEST(CordDataEdgeTest, EdgeDataOnSubstringOfFlat) { + absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ..."; + CordRep* rep = MakeFlat(value); + CordRep* substr = MakeSubstring(1, 20, rep); + EXPECT_EQ(EdgeData(substr), value.substr(1, 20)); + CordRep::Unref(substr); +} + +TEST(CordDataEdgeTest, EdgeDataOnSubstringOfExternal) { + absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ..."; + CordRep* rep = MakeExternal(value); + CordRep* substr = MakeSubstring(1, 20, rep); + EXPECT_EQ(EdgeData(substr), value.substr(1, 20)); + CordRep::Unref(substr); +} + +#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) + +TEST(CordDataEdgeTest, IsDataEdgeOnNullPtr) { + EXPECT_DEATH(IsDataEdge(nullptr), ".*"); +} + +TEST(CordDataEdgeTest, EdgeDataOnNullPtr) { + EXPECT_DEATH(EdgeData(nullptr), ".*"); +} + +TEST(CordDataEdgeTest, EdgeDataOnBtree) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRepBtree* tree = CordRepBtree::New(rep); + EXPECT_DEATH(EdgeData(tree), ".*"); + CordRep::Unref(tree); +} + +TEST(CordDataEdgeTest, EdgeDataOnBadSubstr) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRep* substr = MakeSubstring(1, 18, MakeSubstring(1, 20, rep)); + EXPECT_DEATH(EdgeData(substr), ".*"); + CordRep::Unref(substr); +} + +#endif // GTEST_HAS_DEATH_TEST && !NDEBUG + +} // namespace +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/strings/internal/cord_rep_btree.cc b/absl/strings/internal/cord_rep_btree.cc index 3ebd9f6d..2b592b47 100644 --- a/absl/strings/internal/cord_rep_btree.cc +++ b/absl/strings/internal/cord_rep_btree.cc @@ -22,6 +22,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_consume.h" #include "absl/strings/internal/cord_rep_flat.h" @@ -69,7 +70,7 @@ void DumpAll(const CordRep* rep, bool include_contents, std::ostream& stream, // indentation and prefix / labels keeps us within roughly 80-100 wide. constexpr size_t kMaxDataLength = 60; stream << ", data = \"" - << CordRepBtree::EdgeData(r).substr(0, kMaxDataLength) + << EdgeData(r).substr(0, kMaxDataLength) << (r->length > kMaxDataLength ? "\"..." : "\""); } stream << '\n'; @@ -150,7 +151,7 @@ inline CordRep* MakeSubstring(CordRep* rep, size_t offset) { CordRep* ResizeEdge(CordRep* edge, size_t length, bool is_mutable) { assert(length > 0); assert(length <= edge->length); - assert(CordRepBtree::IsDataEdge(edge)); + assert(IsDataEdge(edge)); if (length >= edge->length) return edge; if (is_mutable && (edge->tag >= FLAT || edge->tag == SUBSTRING)) { @@ -207,7 +208,7 @@ void DeleteSubstring(CordRepSubstring* substring) { // Deletes a leaf node data edge. Requires `IsDataEdge(rep)`. void DeleteLeafEdge(CordRep* rep) { - assert(CordRepBtree::IsDataEdge(rep)); + assert(IsDataEdge(rep)); if (rep->tag >= FLAT) { CordRepFlat::Delete(rep->flat()); } else if (rep->tag == EXTERNAL) { diff --git a/absl/strings/internal/cord_rep_btree.h b/absl/strings/internal/cord_rep_btree.h index df5c994c..0e78e12c 100644 --- a/absl/strings/internal/cord_rep_btree.h +++ b/absl/strings/internal/cord_rep_btree.h @@ -22,6 +22,7 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/optimization.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/string_view.h" @@ -310,13 +311,6 @@ class CordRepBtree : public CordRep { // Requires this instance to be a leaf node, and `index` to be valid index. inline absl::string_view Data(size_t index) const; - static const char* EdgeDataPtr(const CordRep* r); - static absl::string_view EdgeData(const CordRep* r); - - // Returns true if the provided rep is a FLAT, EXTERNAL or a SUBSTRING node - // holding a FLAT or EXTERNAL child rep. - static bool IsDataEdge(const CordRep* rep); - // Diagnostics: returns true if `tree` is valid and internally consistent. // If `shallow` is false, then the provided top level node and all child nodes // below it are recursively checked. If `shallow` is true, only the provided @@ -631,34 +625,11 @@ inline absl::Span CordRepBtree::Edges(size_t begin, return {edges_ + begin, static_cast(end - begin)}; } -inline const char* CordRepBtree::EdgeDataPtr(const CordRep* r) { - assert(IsDataEdge(r)); - size_t offset = 0; - if (r->tag == SUBSTRING) { - offset = r->substring()->start; - r = r->substring()->child; - } - return (r->tag >= FLAT ? r->flat()->Data() : r->external()->base) + offset; -} - -inline absl::string_view CordRepBtree::EdgeData(const CordRep* r) { - return absl::string_view(EdgeDataPtr(r), r->length); -} - inline absl::string_view CordRepBtree::Data(size_t index) const { assert(height() == 0); return EdgeData(Edge(index)); } -inline bool CordRepBtree::IsDataEdge(const CordRep* rep) { - // The fast path is that `rep` is an EXTERNAL or FLAT node, making the below - // if a single, well predicted branch. We then repeat the FLAT or EXTERNAL - // check in the slow path the SUBSTRING check to optimize for the hot path. - if (rep->tag == EXTERNAL || rep->tag >= FLAT) return true; - if (rep->tag == SUBSTRING) rep = rep->substring()->child; - return rep->tag == EXTERNAL || rep->tag >= FLAT; -} - inline CordRepBtree* CordRepBtree::New(int height) { CordRepBtree* tree = new CordRepBtree; tree->length = 0; diff --git a/absl/strings/internal/cord_rep_btree_navigator.cc b/absl/strings/internal/cord_rep_btree_navigator.cc index 19afbe90..9b896a3d 100644 --- a/absl/strings/internal/cord_rep_btree_navigator.cc +++ b/absl/strings/internal/cord_rep_btree_navigator.cc @@ -16,6 +16,7 @@ #include +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" @@ -39,7 +40,7 @@ inline CordRep* Substring(CordRep* rep, size_t offset, size_t n) { assert(n <= rep->length); assert(offset < rep->length); assert(offset <= rep->length - n); - assert(CordRepBtree::IsDataEdge(rep)); + assert(IsDataEdge(rep)); if (n == 0) return nullptr; if (n == rep->length) return CordRep::Ref(rep); diff --git a/absl/strings/internal/cord_rep_btree_reader.cc b/absl/strings/internal/cord_rep_btree_reader.cc index 5dc76966..0d0e8601 100644 --- a/absl/strings/internal/cord_rep_btree_reader.cc +++ b/absl/strings/internal/cord_rep_btree_reader.cc @@ -17,6 +17,7 @@ #include #include "absl/base/config.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree_navigator.h" @@ -44,7 +45,7 @@ absl::string_view CordRepBtreeReader::Read(size_t n, size_t chunk_size, // can directly return the substring into the current data edge as the next // chunk. We can easily establish from the above code that `navigator_.Next()` // has not been called as that requires `chunk_size` to be zero. - if (n < chunk_size) return CordRepBtree::EdgeData(edge).substr(result.n); + if (n < chunk_size) return EdgeData(edge).substr(result.n); // The amount of data taken from the last edge is `chunk_size` and `result.n` // contains the offset into the current edge trailing the read data (which can @@ -60,7 +61,7 @@ absl::string_view CordRepBtreeReader::Read(size_t n, size_t chunk_size, // We did not read all data, return remaining data from current edge. edge = navigator_.Current(); remaining_ -= consumed_by_read + edge->length; - return CordRepBtree::EdgeData(edge).substr(result.n); + return EdgeData(edge).substr(result.n); } } // namespace cord_internal diff --git a/absl/strings/internal/cord_rep_btree_reader.h b/absl/strings/internal/cord_rep_btree_reader.h index 7aa79dbf..8db8f8dd 100644 --- a/absl/strings/internal/cord_rep_btree_reader.h +++ b/absl/strings/internal/cord_rep_btree_reader.h @@ -18,6 +18,7 @@ #include #include "absl/base/config.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree_navigator.h" @@ -167,7 +168,7 @@ inline absl::string_view CordRepBtreeReader::Init(CordRepBtree* tree) { assert(tree != nullptr); const CordRep* edge = navigator_.InitFirst(tree); remaining_ = tree->length - edge->length; - return CordRepBtree::EdgeData(edge); + return EdgeData(edge); } inline absl::string_view CordRepBtreeReader::Next() { @@ -175,7 +176,7 @@ inline absl::string_view CordRepBtreeReader::Next() { const CordRep* edge = navigator_.Next(); assert(edge != nullptr); remaining_ -= edge->length; - return CordRepBtree::EdgeData(edge); + return EdgeData(edge); } inline absl::string_view CordRepBtreeReader::Skip(size_t skip) { @@ -190,7 +191,7 @@ inline absl::string_view CordRepBtreeReader::Skip(size_t skip) { // The combined length of all edges skipped before `pos.edge` is `skip - // pos.offset`, all of which are 'consumed', as well as the current edge. remaining_ -= skip - pos.offset + pos.edge->length; - return CordRepBtree::EdgeData(pos.edge).substr(pos.offset); + return EdgeData(pos.edge).substr(pos.offset); } inline absl::string_view CordRepBtreeReader::Seek(size_t offset) { @@ -199,7 +200,7 @@ inline absl::string_view CordRepBtreeReader::Seek(size_t offset) { remaining_ = 0; return {}; } - absl::string_view chunk = CordRepBtree::EdgeData(pos.edge).substr(pos.offset); + absl::string_view chunk = EdgeData(pos.edge).substr(pos.offset); remaining_ = length() - offset - chunk.length(); return chunk; } diff --git a/absl/strings/internal/cord_rep_btree_test.cc b/absl/strings/internal/cord_rep_btree_test.cc index 1d56b252..51b90db1 100644 --- a/absl/strings/internal/cord_rep_btree_test.cc +++ b/absl/strings/internal/cord_rep_btree_test.cc @@ -25,6 +25,7 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/cleanup/cleanup.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_test_util.h" #include "absl/strings/str_cat.h" @@ -323,30 +324,26 @@ TEST(CordRepBtreeTest, EdgeData) { CordRep* substr2 = MakeSubstring(1, 6, CordRep::Ref(external)); CordRep* bad_substr = MakeSubstring(1, 2, CordRep::Ref(substr1)); - EXPECT_TRUE(CordRepBtree::IsDataEdge(flat)); - EXPECT_THAT(CordRepBtree::EdgeDataPtr(flat), - TypedEq(flat->Data())); - EXPECT_THAT(CordRepBtree::EdgeData(flat), Eq("Hello world")); + EXPECT_TRUE(IsDataEdge(flat)); + EXPECT_THAT(EdgeData(flat).data(), TypedEq(flat->Data())); + EXPECT_THAT(EdgeData(flat), Eq("Hello world")); - EXPECT_TRUE(CordRepBtree::IsDataEdge(external)); - EXPECT_THAT(CordRepBtree::EdgeDataPtr(external), - TypedEq(external->base)); - EXPECT_THAT(CordRepBtree::EdgeData(external), Eq("Hello external")); + EXPECT_TRUE(IsDataEdge(external)); + EXPECT_THAT(EdgeData(external).data(), TypedEq(external->base)); + EXPECT_THAT(EdgeData(external), Eq("Hello external")); - EXPECT_TRUE(CordRepBtree::IsDataEdge(substr1)); - EXPECT_THAT(CordRepBtree::EdgeDataPtr(substr1), - TypedEq(flat->Data() + 1)); - EXPECT_THAT(CordRepBtree::EdgeData(substr1), Eq("ello w")); + EXPECT_TRUE(IsDataEdge(substr1)); + EXPECT_THAT(EdgeData(substr1).data(), TypedEq(flat->Data() + 1)); + EXPECT_THAT(EdgeData(substr1), Eq("ello w")); - EXPECT_TRUE(CordRepBtree::IsDataEdge(substr2)); - EXPECT_THAT(CordRepBtree::EdgeDataPtr(substr2), + EXPECT_TRUE(IsDataEdge(substr2)); + EXPECT_THAT(EdgeData(substr2).data(), TypedEq(external->base + 1)); - EXPECT_THAT(CordRepBtree::EdgeData(substr2), Eq("ello e")); + EXPECT_THAT(EdgeData(substr2), Eq("ello e")); - EXPECT_FALSE(CordRepBtree::IsDataEdge(bad_substr)); + EXPECT_FALSE(IsDataEdge(bad_substr)); #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) - EXPECT_DEATH(CordRepBtree::EdgeData(bad_substr), ".*"); - EXPECT_DEATH(CordRepBtree::EdgeDataPtr(bad_substr), ".*"); + EXPECT_DEATH(EdgeData(bad_substr), ".*"); #endif CordRep::Unref(bad_substr); diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh index 37be5310..0e05564f 100644 --- a/ci/linux_docker_containers.sh +++ b/ci/linux_docker_containers.sh @@ -16,6 +16,6 @@ # Test scripts should source this file to get the identifiers. readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20201026" -readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220113" -readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220113" +readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220217" +readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220217" readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20210617" -- cgit v1.2.3 From 808bc202fc13e85a7948db0d7fb58f0f051200b1 Mon Sep 17 00:00:00 2001 From: imaiguo Date: Wed, 23 Feb 2022 22:56:32 +0800 Subject: Add support of loongarch64 (#1110) --- absl/debugging/internal/examine_stack.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc index 589a3ef3..2fbfea8e 100644 --- a/absl/debugging/internal/examine_stack.cc +++ b/absl/debugging/internal/examine_stack.cc @@ -82,6 +82,8 @@ void* GetProgramCounter(void* vuc) { return reinterpret_cast(context->uc_mcontext.gregs[16]); #elif defined(__e2k__) return reinterpret_cast(context->uc_mcontext.cr0_hi); +#elif defined(__loongarch__) + return reinterpret_cast(context->uc_mcontext.__pc); #else #error "Undefined Architecture." #endif -- cgit v1.2.3 From dfc3fa9b5ae8b204ac83e3f06e4e8626f9bb2bc2 Mon Sep 17 00:00:00 2001 From: Andrew Krasavin Date: Thu, 3 Mar 2022 14:35:39 +0000 Subject: Some trivial OpenBSD-related fixes (#1113) --- absl/base/config.h | 4 ++-- absl/base/internal/raw_logging.cc | 7 ++++--- absl/debugging/internal/elf_mem_image.h | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'absl/debugging') diff --git a/absl/base/config.h b/absl/base/config.h index 373aa0cc..acbdb75c 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -414,7 +414,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || defined(_AIX) || defined(__ros__) || defined(__native_client__) || \ defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__) || \ defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \ - defined(__HAIKU__) + defined(__HAIKU__) || defined(__OpenBSD__) #define ABSL_HAVE_MMAP 1 #endif @@ -425,7 +425,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM #error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ - defined(_AIX) || defined(__ros__) + defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) #define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1 #endif diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index 074e026a..509d7460 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc @@ -36,8 +36,8 @@ // This preprocessor token is also defined in raw_io.cc. If you need to copy // this, consider moving both to config.h instead. #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ - defined(__Fuchsia__) || defined(__native_client__) || \ - defined(__EMSCRIPTEN__) || defined(__ASYLO__) + defined(__Fuchsia__) || defined(__native_client__) || \ + defined(__OpenBSD__) || defined(__EMSCRIPTEN__) || defined(__ASYLO__) #include @@ -50,7 +50,8 @@ // ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall // syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len); // for low level operations that want to avoid libc. -#if (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__) +#if (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && \ + !defined(__ANDROID__) #include #define ABSL_HAVE_SYSCALL_WRITE 1 #define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1 diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index a894bd42..be20256f 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -31,8 +31,8 @@ #error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set #endif -#if defined(__ELF__) && !defined(__native_client__) && !defined(__asmjs__) && \ - !defined(__wasm__) +#if defined(__ELF__) && !defined(__OpenBSD__) && \ + !defined(__native_client__) && !defined(__asmjs__) && !defined(__wasm__) #define ABSL_HAVE_ELF_MEM_IMAGE 1 #endif -- cgit v1.2.3 From f9b99adeddbe71208e65cead5f349add7aa9c9b5 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 7 Mar 2022 22:25:14 -0800 Subject: Export of internal Abseil changes -- 0b01bad05b4cdea647ad274d64af0d6732787a1d by Gennadiy Rozental : Internal change PiperOrigin-RevId: 433124996 Change-Id: I0a081fb5cbb628901e4913a9c587468ca3b3aaa4 GitOrigin-RevId: 0b01bad05b4cdea647ad274d64af0d6732787a1d --- absl/debugging/internal/examine_stack.cc | 10 ++++++++++ absl/debugging/internal/examine_stack.h | 15 +++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc index 2fbfea8e..81d216f9 100644 --- a/absl/debugging/internal/examine_stack.cc +++ b/absl/debugging/internal/examine_stack.cc @@ -37,6 +37,16 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { +namespace { +ABSL_CONST_INIT SymbolizeUrlEmitter debug_stack_trace_hook = nullptr; +} // namespace + +void RegisterDebugStackTraceHook(SymbolizeUrlEmitter hook) { + debug_stack_trace_hook = hook; +} + +SymbolizeUrlEmitter GetDebugStackTraceHook() { return debug_stack_trace_hook; } + // Returns the program counter from signal context, nullptr if // unknown. vuc is a ucontext_t*. We use void* to avoid the use of // ucontext_t on non-POSIX systems. diff --git a/absl/debugging/internal/examine_stack.h b/absl/debugging/internal/examine_stack.h index 39336913..61f0056f 100644 --- a/absl/debugging/internal/examine_stack.h +++ b/absl/debugging/internal/examine_stack.h @@ -23,6 +23,21 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { +// Type of function used for printing in stack trace dumping, etc. +// We avoid closures to keep things simple. +typedef void OutputWriter(const char*, void*); + +// RegisterDebugStackTraceHook() allows to register a single routine +// `hook` that is called each time DumpStackTrace() is called. +// `hook` may be called from a signal handler. +typedef void (*SymbolizeUrlEmitter)(void* const stack[], int depth, + OutputWriter writer, void* writer_arg); + +// Registration of SymbolizeUrlEmitter for use inside of a signal handler. +// This is inherently unsafe and must be signal safe code. +void RegisterDebugStackTraceHook(SymbolizeUrlEmitter hook); +SymbolizeUrlEmitter GetDebugStackTraceHook(); + // Returns the program counter from signal context, or nullptr if // unknown. `vuc` is a ucontext_t*. We use void* to avoid the use of // ucontext_t on non-POSIX systems. -- cgit v1.2.3 From c5a424a2a21005660b182516eb7a079cd8021699 Mon Sep 17 00:00:00 2001 From: Thomas Klausner Date: Tue, 8 Mar 2022 22:01:16 +0100 Subject: Add NetBSD support (#1121) --- absl/base/config.h | 5 +++-- absl/debugging/internal/elf_mem_image.cc | 4 ++++ absl/debugging/internal/vdso_support.cc | 9 +++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) (limited to 'absl/debugging') diff --git a/absl/base/config.h b/absl/base/config.h index acbdb75c..cd7781c0 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -414,7 +414,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || defined(_AIX) || defined(__ros__) || defined(__native_client__) || \ defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__) || \ defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \ - defined(__HAIKU__) || defined(__OpenBSD__) + defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) #define ABSL_HAVE_MMAP 1 #endif @@ -425,7 +425,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM #error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ - defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) + defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) || \ + defined(__NetBSD__) #define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1 #endif diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc index 29a28181..a9d66714 100644 --- a/absl/debugging/internal/elf_mem_image.cc +++ b/absl/debugging/internal/elf_mem_image.cc @@ -351,7 +351,11 @@ void ElfMemImage::SymbolIterator::Update(int increment) { const ElfW(Versym) *version_symbol = image->GetVersym(index_); ABSL_RAW_CHECK(symbol && version_symbol, ""); const char *const symbol_name = image->GetDynstr(symbol->st_name); +#if defined(__NetBSD__) + const int version_index = version_symbol->vs_vers & VERSYM_VERSION; +#else const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION; +#endif const ElfW(Verdef) *version_definition = nullptr; const char *version_name = ""; if (symbol->st_shndx == SHN_UNDEF) { diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc index 8a015d55..c655cf45 100644 --- a/absl/debugging/internal/vdso_support.cc +++ b/absl/debugging/internal/vdso_support.cc @@ -50,6 +50,10 @@ #define AT_SYSINFO_EHDR 33 // for crosstoolv10 #endif +#if defined(__NetBSD__) +using Elf32_auxv_t = Aux32Info; +using Elf64_auxv_t = Aux64Info; +#endif #if defined(__FreeBSD__) #if defined(__ELF_WORD_SIZE) && __ELF_WORD_SIZE == 64 using Elf64_auxv_t = Elf64_Auxinfo; @@ -106,8 +110,13 @@ const void *VDSOSupport::Init() { ElfW(auxv_t) aux; while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) { if (aux.a_type == AT_SYSINFO_EHDR) { +#if defined(__NetBSD__) + vdso_base_.store(reinterpret_cast(aux.a_v), + std::memory_order_relaxed); +#else vdso_base_.store(reinterpret_cast(aux.a_un.a_val), std::memory_order_relaxed); +#endif break; } } -- cgit v1.2.3 From e6ae2641f6261c67adb5766ccbcf953e2bb0a8fd Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 16 Mar 2022 09:53:25 -0700 Subject: Export of internal Abseil changes -- c49308e5361da572b5accdfe664757ca6bf7fed1 by Derek Mauro : Disable TestArmThumbOverlap on platforms that don't support it TestArmThumbOverlap includes a pair of test functions, one built in arm mode and the other built in thumb mode. Unfortunately when configured for armv6 hardfloat, gcc refuses to build any functions in thumb mode (even if they don't actually use floating point) Closes #1112 PiperOrigin-RevId: 435078532 Change-Id: I090623d0f89839a5f9dde831756aba5267c9a45c GitOrigin-RevId: c49308e5361da572b5accdfe664757ca6bf7fed1 --- absl/debugging/symbolize_test.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'absl/debugging') diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index a62fa35d..3165c6ed 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -483,7 +483,8 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { } } -#if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) +#if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) && \ + ((__ARM_ARCH >= 7) || !defined(__ARM_PCS_VFP)) // Test that we correctly identify bounds of Thumb functions on ARM. // // Thumb functions have the lowest-order bit set in their addresses in the ELF @@ -502,6 +503,10 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { // bit in the Thumb function's entry point. It will correctly compute the end of // the Thumb function, it will find no overlap between the Thumb and ARM // functions, and it will return the name of the ARM function. +// +// Unfortunately we cannot perform this test on armv6 or lower systems that use +// the hard float ABI because gcc refuses to compile thumb functions on such +// systems with a "sorry, unimplemented: Thumb-1 hard-float VFP ABI" error. __attribute__((target("thumb"))) int ArmThumbOverlapThumb(int x) { return x * x * x; @@ -521,7 +526,8 @@ void ABSL_ATTRIBUTE_NOINLINE TestArmThumbOverlap() { #endif } -#endif // defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) +#endif // defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) && ((__ARM_ARCH >= 7) + // || !defined(__ARM_PCS_VFP)) #elif defined(_WIN32) #if !defined(ABSL_CONSUME_DLL) @@ -596,7 +602,8 @@ int main(int argc, char **argv) { TestWithPCInsideInlineFunction(); TestWithPCInsideNonInlineFunction(); TestWithReturnAddress(); -#if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) +#if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) && \ + ((__ARM_ARCH >= 7) || !defined(__ARM_PCS_VFP)) TestArmThumbOverlap(); #endif #endif -- cgit v1.2.3 From 9f5b2c782ad50df4692bc66f1687e1f4d43c7308 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 17 Mar 2022 09:43:32 -0700 Subject: Export of internal Abseil changes -- 399d051d30f7a78c367bb1dc08829ffacbb619a6 by Abseil Team : Fix a glitch in symbolization which could result in the same address being correctly symbolized and "(unknown)" in the same crash report. PiperOrigin-RevId: 435371003 Change-Id: I9f6a5684144be6d3d366584601d79fda9eefdce6 -- 5dad813de52773e0bb09c6b2351e1bbadb53deac by Abseil Team : Fix ABSL_HAVE_MMAP check in direct_mmap.h This change makes the check for ABSL_HAVE_MMAP match the other checks in absl. This fixes builds where ABSL_HAVE_MMAP is not defined. PiperOrigin-RevId: 435190242 Change-Id: I11638ef315849cafcf4ea1611eee1a98c80e7dcb GitOrigin-RevId: 399d051d30f7a78c367bb1dc08829ffacbb619a6 --- absl/base/internal/direct_mmap.h | 2 +- absl/debugging/internal/examine_stack.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'absl/debugging') diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h index 274054cd..a01d6122 100644 --- a/absl/base/internal/direct_mmap.h +++ b/absl/base/internal/direct_mmap.h @@ -20,7 +20,7 @@ #include "absl/base/config.h" -#if ABSL_HAVE_MMAP +#ifdef ABSL_HAVE_MMAP #include diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc index 81d216f9..e0950b72 100644 --- a/absl/debugging/internal/examine_stack.cc +++ b/absl/debugging/internal/examine_stack.cc @@ -146,7 +146,8 @@ static void DumpPCAndFrameSizeAndSymbol(void (*writerfn)(const char*, void*), const char* const prefix) { char tmp[1024]; const char* symbol = "(unknown)"; - if (absl::Symbolize(symbolize_pc, tmp, sizeof(tmp))) { + if (absl::Symbolize(symbolize_pc, tmp, sizeof(tmp)) || + (pc != symbolize_pc && absl::Symbolize(pc, tmp, sizeof(tmp)))) { symbol = tmp; } char buf[1024]; -- cgit v1.2.3 From 6c8dab80c06820f475ce0a1fe873b8022cb274f6 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 18 Mar 2022 14:42:21 -0700 Subject: Export of internal Abseil changes -- f3ac7ee28fc7de737bc9e2e1d10ff7739781d645 by Gennadiy Rozental : Internal change PiperOrigin-RevId: 435739199 Change-Id: I8f854b742418a237f9060e4b9f23d0f20baf0bdf -- fe1329708cb40da8e72e53e4eaad79112bdb79ea by Abseil Team : Port SwissTable internals comments from github.com/google/cwisstable to Abseil. PiperOrigin-RevId: 435719801 Change-Id: I2270cc93aaa5d3d57954a8cea7e570b72b6c3956 -- a6e6fcd4b944ce370ac3307e848645c27bf21e47 by Derek Mauro : Internal change PiperOrigin-RevId: 435716325 Change-Id: I77999f69e176ee6c0d18e7c3329a7c336164f0fc GitOrigin-RevId: f3ac7ee28fc7de737bc9e2e1d10ff7739781d645 --- absl/container/internal/raw_hash_set.cc | 2 + absl/container/internal/raw_hash_set.h | 434 +++++++++++++++++++++++-------- absl/debugging/internal/examine_stack.cc | 211 +++++++++++---- absl/debugging/internal/examine_stack.h | 21 +- 4 files changed, 496 insertions(+), 172 deletions(-) (limited to 'absl/debugging') diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 687bcb8a..61bdb773 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -23,6 +23,8 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { +// A single block of empty control bytes for tables without any slots allocated. +// This enables removing a branch in the hot path of find(). alignas(16) ABSL_CONST_INIT ABSL_DLL const ctrl_t kEmptyGroup[16] = { ctrl_t::kSentinel, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 0daf7223..d24bbe83 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -53,51 +53,125 @@ // // IMPLEMENTATION DETAILS // -// The table stores elements inline in a slot array. In addition to the slot -// array the table maintains some control state per slot. The extra state is one -// byte per slot and stores empty or deleted marks, or alternatively 7 bits from -// the hash of an occupied slot. The table is split into logical groups of -// slots, like so: +// # Table Layout +// +// A raw_hash_set's backing array consists of control bytes followed by slots +// that may or may not contain objects. +// +// The layout of the backing array, for `capacity` slots, is thus, as a +// pseudo-struct: +// +// struct BackingArray { +// // Control bytes for the "real" slots. +// ctrl_t ctrl[capacity]; +// // Always `ctrl_t::kSentinel`. This is used by iterators to find when to +// // stop and serves no other purpose. +// ctrl_t sentinel; +// // A copy of the first `kWidth - 1` elements of `ctrl`. This is used so +// // that if a probe sequence picks a value near the end of `ctrl`, +// // `Group` will have valid control bytes to look at. +// ctrl_t clones[kWidth - 1]; +// // The actual slot data. +// slot_type slots[capacity]; +// }; +// +// The length of this array is computed by `AllocSize()` below. +// +// Control bytes (`ctrl_t`) are bytes (collected into groups of a +// platform-specific size) that define the state of the corresponding slot in +// the slot array. Group manipulation is tightly optimized to be as efficient +// as possible: SSE and friends on x86, clever bit operations on other arches. // // Group 1 Group 2 Group 3 // +---------------+---------------+---------------+ // | | | | | | | | | | | | | | | | | | | | | | | | | // +---------------+---------------+---------------+ // -// On lookup the hash is split into two parts: -// - H2: 7 bits (those stored in the control bytes) -// - H1: the rest of the bits -// The groups are probed using H1. For each group the slots are matched to H2 in -// parallel. Because H2 is 7 bits (128 states) and the number of slots per group -// is low (8 or 16) in almost all cases a match in H2 is also a lookup hit. +// Each control byte is either a special value for empty slots, deleted slots +// (sometimes called *tombstones*), and a speical end-of-table marker used by +// iterators, or, if occupied, seven bits (H2) from the hash of the value in the +// corresponding slot. +// +// Storing control bytes in a separate array also has beneficial cache effects, +// since more logical slots will fit into a cache line. +// +// # Table operations. +// +// The key operations are `insert`, `find`, and `erase_at`; the operations below // -// On insert, once the right group is found (as in lookup), its slots are -// filled in order. +// `insert` and `erase` are implemented in terms of find, so we describe that +// one first. To `find` a value `x`, we compute `hash(x)`. From `H1(hash(x))` +// and the capacity, we construct a `probe_seq` that visits every group of +// slots in some interesting order. // -// On erase a slot is cleared. In case the group did not have any empty slots -// before the erase, the erased slot is marked as deleted. +// We now walk through these indices. At each index, we select the entire group +// starting with that index and extract potential candidates: occupied slots +// with a control byte equal to `H2(hash(x))`. If we find an empty slot in the +// group, we stop and return an error. Each candidate slot `y` is compared with +// `x`; if `x == y`, we are done and return `&y`; otherwise we contine to the +// next probe index. Tombstones effectively behave like full slots that never +// match the value we're looking for. // -// Groups without empty slots (but maybe with deleted slots) extend the probe -// sequence. The probing algorithm is quadratic. Given N the number of groups, -// the probing function for the i'th probe is: +// The `H2` bits ensure that if we perform a ==, a false positive is very very +// rare (assuming the hash function looks enough like a random oracle). To see +// this, note that in a group, there will be at most 8 or 16 `H2` values, but +// an `H2` can be any one of 128 values. Viewed as a birthday attack, we can use +// the rule of thumb that the probability of a collision among n choices of m +// symbols is `p(n, m) ~ n^2/2m. In table form: // -// P(0) = H1 % N +// n | p(n) | n | p(n) +// 0 | 0.000 | 8 | 0.250 +// 1 | 0.004 | 9 | 0.316 +// 2 | 0.016 | 10 | 0.391 +// 3 | 0.035 | 11 | 0.473 +// 4 | 0.062 | 12 | 0.562 +// 5 | 0.098 | 13 | 0.660 +// 6 | 0.141 | 14 | 0.766 +// 7 | 0.191 | 15 | 0.879 // -// P(i) = (P(i - 1) + i) % N +// The rule of thumb breaks down at around `n = 12`, but such groups would only +// occur for tables close to their load factor. This is far better than an +// ordinary open-addressing table, which needs to perform an == at every step of +// the probe sequence. These probabilities don't tell the full story (for +// example, because elements are inserted into a group from the front, and +// candidates are =='ed from the front, the collision is only effective in +// rare cases e.g. another probe sequence inserted into a deleted slot in front +// of us). // -// This probing function guarantees that after N probes, all the groups of the -// table will be probed exactly once. +// `insert` is implemented in terms of `unchecked_insert`, which inserts a +// value presumed to not be in the table (violating this requirement will cause +// the table to behave erratically). Given `x` and its hash `hash(x)`, to insert +// it, we construct a `probe_seq` once again, and use it to find the first +// group with an unoccupied (empty *or* deleted) slot. We place `x` into the +// first such slot in the group and mark it as full with `x`'s H2. // -// The control state and slot array are stored contiguously in a shared heap -// allocation. The layout of this allocation is: `capacity()` control bytes, -// one sentinel control byte, `Group::kWidth - 1` cloned control bytes, -// , `capacity()` slots. The sentinel control byte is used in -// iteration so we know when we reach the end of the table. The cloned control -// bytes at the end of the table are cloned from the beginning of the table so -// groups that begin near the end of the table can see a full group. In cases in -// which there are more than `capacity()` cloned control bytes, the extra bytes -// are `kEmpty`, and these ensure that we always see at least one empty slot and -// can stop an unsuccessful search. +// To `insert`, we compose `unchecked_insert` with `find`. We compute `h(x)` and +// perform a `find` to see if it's already present; if it is, we're done. If +// it's not, we may decide the table is getting overcrowded (i.e. the load +// factor is greater than 7/8 for big tables; `is_small()` tables use a max load +// factor of 1); in this case, we allocate a bigger array, `unchecked_insert` +// each element of the table into the new array (we know that no insertion here +// will insert an already-present value), and discard the old backing array. At +// this point, we may `unchecked_insert` the value `x`. +// +// Below, `unchecked_insert` is partly implemented by `prepare_insert`, which +// presents a viable, intialized slot pointee to the caller. +// +// `erase` is implemented in terms of `erase_at`, which takes an index to a +// slot. Given an offset, we simply create a tombstone and destroy its contents. +// If we can prove that the slot would not appear in a probe sequence, we can +// make the slot as empty, instead. We can prove this by observing that if a +// group has any empty slots, it has never been full (assuming we never create +// an empty slot in a group with no empties, which this heuristic guarantees we +// never do) and find would stop at this group anyways (since it does not probe +// beyond groups with empties). +// +// `erase` is `erase_at` composed with `find`: if we +// have a value `x`, we can perform a `find`, and then `erase_at` the resulting +// slot. +// +// To iterate, we simply traverse the array, skipping empty and deleted slots +// and stopping when we hit a `kSentinel`. #ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ #define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ @@ -142,14 +216,36 @@ template void SwapAlloc(AllocType& /*lhs*/, AllocType& /*rhs*/, std::false_type /* propagate_on_container_swap */) {} +// The state for a probe sequence. +// +// Currently, the sequence is a triangular progression of the form +// +// p(i) := Width * (i^2 - i)/2 + hash (mod mask + 1) +// +// The use of `Width` ensures that each probe step does not overlap groups; +// the sequence effectively outputs the addresses of *groups* (although not +// necessarily aligned to any boundary). The `Group` machinery allows us +// to check an entire group with minimal branching. +// +// Wrapping around at `mask + 1` is important, but not for the obvious reason. +// As described above, the first few entries of the control byte array +// is mirrored at the end of the array, which `Group` will find and use +// for selecting candidates. However, when those candidates' slots are +// actually inspected, there are no corresponding slots for the cloned bytes, +// so we need to make sure we've treated those offsets as "wrapping around". template class probe_seq { public: + // Creates a new probe sequence using `hash` as the initial value of the + // sequence and `mask` (usually the capacity of the table) as the mask to + // apply to each value in the progression. probe_seq(size_t hash, size_t mask) { assert(((mask + 1) & mask) == 0 && "not a mask"); mask_ = mask; offset_ = hash & mask_; } + + // The offset within the table, i.e., the value `p(i)` above. size_t offset() const { return offset_; } size_t offset(size_t i) const { return (offset_ + i) & mask_; } @@ -158,7 +254,7 @@ class probe_seq { offset_ += index_; offset_ &= mask_; } - // 0-based probe index. The i-th probe in the probe sequence. + // 0-based probe index, a multiple of `Width`. size_t index() const { return index_; } private: @@ -182,9 +278,9 @@ struct IsDecomposable : std::false_type {}; template struct IsDecomposable< - absl::void_t(), - std::declval()...))>, + absl::void_t(), + std::declval()...))>, Policy, Hash, Eq, Ts...> : std::true_type {}; // TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it. @@ -204,14 +300,20 @@ uint32_t TrailingZeros(T x) { return static_cast(countr_zero(x)); } -// An abstraction over a bitmask. It provides an easy way to iterate through the -// indexes of the set bits of a bitmask. When Shift=0 (platforms with SSE), -// this is a true bitmask. On non-SSE, platforms the arithematic used to -// emulate the SSE behavior works in bytes (Shift=3) and leaves each bytes as -// either 0x00 or 0x80. +// A abstract bitmask, such as that emitted by a SIMD instruction. +// +// Specifically, this type implements a simple bitset whose representation is +// controlled by `SignificantBits` and `Shift`. `SignificantBits` is the number +// of abstract bits in the bitset, while `Shift` is the log-base-two of the +// width of an abstract bit in the representation. +// +// For example, when `SignificantBits` is 16 and `Shift` is zero, this is just +// an ordinary 16-bit bitset occupying the low 16 bits of `mask`. When +// `SignificantBits` is 8 and `Shift` is 3, abstract bits are represented as +// the bytes `0x00` and `0x80`, and it occupies all 64 bits of the bitmask. // // For example: -// for (int i : BitMask(0x5)) -> yields 0, 2 +// for (int i : BitMask(0b101)) -> yields 0, 2 // for (int i : BitMask(0x0000000080800000)) -> yields 2, 3 template class BitMask { @@ -219,7 +321,7 @@ class BitMask { static_assert(Shift == 0 || Shift == 3, ""); public: - // These are useful for unit tests (gunit). + // BitMask is an iterator over the indices of its abstract bits. using value_type = int; using iterator = BitMask; using const_iterator = BitMask; @@ -231,20 +333,26 @@ class BitMask { } explicit operator bool() const { return mask_ != 0; } uint32_t operator*() const { return LowestBitSet(); } + + BitMask begin() const { return *this; } + BitMask end() const { return BitMask(0); } + + // Returns the index of the lowest *abstract* bit set in `self`. uint32_t LowestBitSet() const { return container_internal::TrailingZeros(mask_) >> Shift; } + + // Returns the index of the highest *abstract* bit set in `self`. uint32_t HighestBitSet() const { return static_cast((bit_width(mask_) - 1) >> Shift); } - BitMask begin() const { return *this; } - BitMask end() const { return BitMask(0); } - + // Return the number of trailing zero *abstract* bits. uint32_t TrailingZeros() const { return container_internal::TrailingZeros(mask_) >> Shift; } + // Return the number of leading zero *abstract* bits. uint32_t LeadingZeros() const { constexpr int total_significant_bits = SignificantBits << Shift; constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits; @@ -265,8 +373,22 @@ class BitMask { using h2_t = uint8_t; // The values here are selected for maximum performance. See the static asserts -// below for details. We use an enum class so that when strict aliasing is -// enabled, the compiler knows ctrl_t doesn't alias other types. +// below for details. + +// A `ctrl_t` is a single control byte, which can have one of four +// states: empty, deleted, full (which has an associated seven-bit h2_t value) +// and the sentinel. They have the following bit patterns: +// +// empty: 1 0 0 0 0 0 0 0 +// deleted: 1 1 1 1 1 1 1 0 +// full: 0 h h h h h h h // h represents the hash bits. +// sentinel: 1 1 1 1 1 1 1 1 +// +// These values are specifically tuned for SSE-flavored SIMD. +// The static_asserts below detail the source of these choices. +// +// We use an enum class so that when strict aliasing is enabled, the compiler +// knows ctrl_t doesn't alias other types. enum class ctrl_t : int8_t { kEmpty = -128, // 0b10000000 kDeleted = -2, // 0b11111110 @@ -299,10 +421,12 @@ static_assert(ctrl_t::kDeleted == static_cast(-2), "ctrl_t::kDeleted must be -2 to make the implementation of " "ConvertSpecialToEmptyAndFullToDeleted efficient"); -// A single block of empty control bytes for tables without any slots allocated. -// This enables removing a branch in the hot path of find(). ABSL_DLL extern const ctrl_t kEmptyGroup[16]; + +// Returns a pointer to a control byte group that can be used by empty tables. inline ctrl_t* EmptyGroup() { + // Const must be cast away here; no uses of this function will actually write + // to it, because it is only used for empty tables. return const_cast(kEmptyGroup); } @@ -310,28 +434,61 @@ inline ctrl_t* EmptyGroup() { // randomize insertion order within groups. bool ShouldInsertBackwards(size_t hash, const ctrl_t* ctrl); -// Returns a hash seed. +// Returns a per-table, hash salt, which changes on resize. This gets mixed into +// H1 to randomize iteration order per-table. // // The seed consists of the ctrl_ pointer, which adds enough entropy to ensure // non-determinism of iteration order in most cases. -inline size_t HashSeed(const ctrl_t* ctrl) { +inline size_t PerTableSalt(const ctrl_t* ctrl) { // The low bits of the pointer have little or no entropy because of // alignment. We shift the pointer to try to use higher entropy bits. A // good number seems to be 12 bits, because that aligns with page size. return reinterpret_cast(ctrl) >> 12; } - +// Extracts the H1 portion of a hash: 57 bits mixed with a per-table salt. inline size_t H1(size_t hash, const ctrl_t* ctrl) { - return (hash >> 7) ^ HashSeed(ctrl); + return (hash >> 7) ^ PerTableSalt(ctrl); } + +// Extracts the H2 portion of a hash: the 7 bits not used for H1. +// +// Thse are used used as an occupied control byte. inline h2_t H2(size_t hash) { return hash & 0x7F; } +// Helpers for checking the state of a control byte. inline bool IsEmpty(ctrl_t c) { return c == ctrl_t::kEmpty; } inline bool IsFull(ctrl_t c) { return c >= static_cast(0); } inline bool IsDeleted(ctrl_t c) { return c == ctrl_t::kDeleted; } inline bool IsEmptyOrDeleted(ctrl_t c) { return c < ctrl_t::kSentinel; } #if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2 +// Quick eference guide for intrinsics used below: +// +// * __m128i: An XMM (128-bit) word. +// +// * _mm_setzero_si128: Returns a zero vector. +// * _mm_set1_epi8: Returns a vector with the same i8 in each lane. +// +// * _mm_subs_epi8: Saturating-subtracts two i8 vectors. +// * _mm_and_si128: Ands two i128s together. +// * _mm_or_si128: Ors two i128s together. +// * _mm_andnot_si128: And-nots two i128s together. +// +// * _mm_cmpeq_epi8: Component-wise compares two i8 vectors for equality, +// filling each lane with 0x00 or 0xff. +// * _mm_cmpgt_epi8: Same as above, but using > rather than ==. +// +// * _mm_loadu_si128: Performs an unaligned load of an i128. +// * _mm_storeu_si128: Performs an unaligned store of a i128. +// +// * _mm_sign_epi8: Retains, negates, or zeroes each i8 lane of the first +// argument if the corresponding lane of the second +// argument is positive, negative, or zero, respectively. +// * _mm_movemask_epi8: Selects the sign bit out of each i8 lane and produces a +// bitmask consisting of those bits. +// * _mm_shuffle_epi8: Selects i8s from the first argument, using the low +// four bits of each i8 lane in the second argument as +// indices. // https://github.com/abseil/abseil-cpp/issues/209 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853 @@ -377,9 +534,8 @@ struct GroupSse2Impl { // Returns a bitmask representing the positions of empty or deleted slots. BitMask MatchEmptyOrDeleted() const { auto special = _mm_set1_epi8(static_cast(ctrl_t::kSentinel)); - return BitMask( - static_cast( - _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)))); + return BitMask(static_cast( + _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)))); } // Returns the number of trailing empty or deleted elements in the group. @@ -464,26 +620,32 @@ using Group = GroupSse2Impl; using Group = GroupPortableImpl; #endif -// The number of cloned control bytes that we copy from the beginning to the -// end of the control bytes array. +// Returns he number of "cloned control bytes". +// +// This is the number of control bytes that are present both at the beginning +// of the control byte array and at the end, such that we can create a +// `Group::kWidth`-width probe window starting from any control byte. constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } template class raw_hash_set; +// Returns whether `n` is a valid capacity (i.e., number of slots). +// +// A valid capacity is a non-zero integer `2^m - 1`. inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } +// Applies the following mapping to every byte in the control array: +// * kDeleted -> kEmpty +// * kEmpty -> kEmpty +// * _ -> kDeleted // PRECONDITION: // IsValidCapacity(capacity) // ctrl[capacity] == ctrl_t::kSentinel // ctrl[i] != ctrl_t::kSentinel for all i < capacity -// Applies mapping for every byte in ctrl: -// DELETED -> EMPTY -// EMPTY -> EMPTY -// FULL -> DELETED void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity); -// Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1. +// Converts `n` into the next valid capacity, per `IsValidCapacity`. inline size_t NormalizeCapacity(size_t n) { return n ? ~size_t{} >> countl_zero(n) : 1; } @@ -496,8 +658,8 @@ inline size_t NormalizeCapacity(size_t n) { // never need to probe (the whole table fits in one group) so we don't need a // load factor less than 1. -// Given `capacity` of the table, returns the size (i.e. number of full slots) -// at which we should grow the capacity. +// Given `capacity`, applies the load factor; i.e., it returns the maximum +// number of values we should put into the table before a resizing rehash. inline size_t CapacityToGrowth(size_t capacity) { assert(IsValidCapacity(capacity)); // `capacity*7/8` @@ -507,8 +669,12 @@ inline size_t CapacityToGrowth(size_t capacity) { } return capacity - capacity / 8; } -// From desired "growth" to a lowerbound of the necessary capacity. -// Might not be a valid one and requires NormalizeCapacity(). + +// Given `growth`, "unapplies" the load factor to find how large the capacity +// should be to stay within the load factor. +// +// This might not be a valid capacity and `NormalizeCapacity()` should be +// called on this. inline size_t GrowthToLowerboundCapacity(size_t growth) { // `growth*8/7` if (Group::kWidth == 8 && growth == 7) { @@ -555,37 +721,33 @@ struct FindInfo { size_t probe_length; }; -// The representation of the object has two modes: -// - small: For capacities < kWidth-1 -// - large: For the rest. +// Whether a table is "small". A small table fits entirely into a probing +// group, i.e., has a capacity < `Group::kWidth`. // -// Differences: -// - In small mode we are able to use the whole capacity. The extra control -// bytes give us at least one "empty" control byte to stop the iteration. -// This is important to make 1 a valid capacity. +// In small mode we are able to use the whole capacity. The extra control +// bytes give us at least one "empty" control byte to stop the iteration. +// This is important to make 1 a valid capacity. // -// - In small mode only the first `capacity()` control bytes after the -// sentinel are valid. The rest contain dummy ctrl_t::kEmpty values that do not -// represent a real slot. This is important to take into account on -// find_first_non_full(), where we never try ShouldInsertBackwards() for -// small tables. +// In small mode only the first `capacity` control bytes after the sentinel +// are valid. The rest contain dummy ctrl_t::kEmpty values that do not +// represent a real slot. This is important to take into account on +// `find_first_or_null()`, where we never try +// `ShouldInsertBackwards()` for small tables. inline bool is_small(size_t capacity) { return capacity < Group::kWidth - 1; } +// Begins a probing operation on `ctrl`, using `hash`. inline probe_seq probe(const ctrl_t* ctrl, size_t hash, size_t capacity) { return probe_seq(H1(hash, ctrl), capacity); } -// Probes the raw_hash_set with the probe sequence for hash and returns the -// pointer to the first empty or deleted slot. -// NOTE: this function must work with tables having both ctrl_t::kEmpty and -// ctrl_t::kDeleted in one group. Such tables appears during -// drop_deletes_without_resize. +// Probes an array of control bits using a probe sequence derived from `hash`, +// and returns the offset corresponding to the first deleted or empty slot. +// +// Behavior when the entire table is full is undefined. // -// This function is very useful when insertions happen and: -// - the input is already a set -// - there are enough slots -// - the element with the hash is not in the table +// NOTE: this function must work with tables having both empty and deleted +// slots in the same group. Such tables appear during `erase()`. template inline FindInfo find_first_non_full(const ctrl_t* ctrl, size_t hash, size_t capacity) { @@ -615,7 +777,8 @@ inline FindInfo find_first_non_full(const ctrl_t* ctrl, size_t hash, // corresponding translation unit. extern template FindInfo find_first_non_full(const ctrl_t*, size_t, size_t); -// Reset all ctrl bytes back to ctrl_t::kEmpty, except the sentinel. +// Sets `ctrl` to `{kEmpty, kSentinel, ..., kEmpty}`, marking the entire +// array as deleted. inline void ResetCtrl(size_t capacity, ctrl_t* ctrl, const void* slot, size_t slot_size) { std::memset(ctrl, static_cast(ctrl_t::kEmpty), @@ -624,8 +787,10 @@ inline void ResetCtrl(size_t capacity, ctrl_t* ctrl, const void* slot, SanitizerPoisonMemoryRegion(slot, slot_size * capacity); } -// Sets the control byte, and if `i < NumClonedBytes()`, set the cloned byte -// at the end too. +// Sets `ctrl[i]` to `h`. +// +// Unlike setting it directly, this function will perform bounds checks and +// mirror the value to the cloned tail if necessary. inline void SetCtrl(size_t i, ctrl_t h, size_t capacity, ctrl_t* ctrl, const void* slot, size_t slot_size) { assert(i < capacity); @@ -641,25 +806,28 @@ inline void SetCtrl(size_t i, ctrl_t h, size_t capacity, ctrl_t* ctrl, ctrl[((i - NumClonedBytes()) & capacity) + (NumClonedBytes() & capacity)] = h; } +// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`. inline void SetCtrl(size_t i, h2_t h, size_t capacity, ctrl_t* ctrl, const void* slot, size_t slot_size) { SetCtrl(i, static_cast(h), capacity, ctrl, slot, slot_size); } -// The allocated block consists of `capacity + 1 + NumClonedBytes()` control -// bytes followed by `capacity` slots, which must be aligned to `slot_align`. -// SlotOffset returns the offset of the slots into the allocated block. +// Given the capacity of a table, computes the offset (from the start of the +// backing allocation) at which the slots begin. inline size_t SlotOffset(size_t capacity, size_t slot_align) { assert(IsValidCapacity(capacity)); const size_t num_control_bytes = capacity + 1 + NumClonedBytes(); return (num_control_bytes + slot_align - 1) & (~slot_align + 1); } -// Returns the size of the allocated block. See also above comment. +// Given the capacity of a table, computes the total size of the backing +// array. inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align) { return SlotOffset(capacity, slot_align) + capacity * slot_size; } +// A SwissTable. +// // Policy: a policy defines how to perform different operations on // the slots of the hashtable (see hash_policy_traits.h for the full interface // of policy). @@ -812,6 +980,10 @@ class raw_hash_set { ABSL_ASSUME(ctrl != nullptr); } + // Fixes up `ctrl_` to point to a full by advancing it and `slot_` until + // they reach one. + // + // If a sentinel is reached, we null both of them out instead. void skip_empty_or_deleted() { while (IsEmptyOrDeleted(*ctrl_)) { uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted(); @@ -1108,8 +1280,7 @@ class raw_hash_set { // m.insert(std::make_pair("abc", 42)); // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc // bug. - template = 0, - class T2 = T, + template = 0, class T2 = T, typename std::enable_if::value, int>::type = 0, T* = nullptr> std::pair insert(T&& value) { @@ -1616,10 +1787,10 @@ class raw_hash_set { slot_type&& slot; }; - // "erases" the object from the container, except that it doesn't actually - // destroy the object. It only updates all the metadata of the class. - // This can be used in conjunction with Policy::transfer to move the object to - // another place. + // Erases, but does not destroy, the value pointed to by `it`. + // + // This merely updates the pertinent control byte. This can be used in + // conjunction with Policy::transfer to move the object to another place. void erase_meta_only(const_iterator it) { assert(IsFull(*it.inner_.ctrl_) && "erasing a dangling iterator"); --size_; @@ -1642,6 +1813,11 @@ class raw_hash_set { infoz().RecordErase(); } + // Allocates a backing array for `self` and initializes its control bytes. + // This reads `capacity_` and updates all other fields based on the result of + // the allocation. + // + // This does not free the currently held array; `capacity_` must be nonzero. void initialize_slots() { assert(capacity_); // Folks with custom allocators often make unwarranted assumptions about the @@ -1670,6 +1846,10 @@ class raw_hash_set { infoz().RecordStorageChanged(size_, capacity_); } + // Destroys all slots in the backing array, frees the backing array, and + // clears all top-level book-keeping data. + // + // This essentially implements `map = raw_hash_set();`. void destroy_slots() { if (!capacity_) return; for (size_t i = 0; i != capacity_; ++i) { @@ -1720,6 +1900,9 @@ class raw_hash_set { infoz().RecordRehash(total_probe_length); } + // Prunes control bytes to remove as many tombstones as possible. + // + // See the comment on `rehash_and_grow_if_necessary()`. void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE { assert(IsValidCapacity(capacity_)); assert(!is_small(capacity_)); @@ -1786,6 +1969,11 @@ class raw_hash_set { infoz().RecordRehash(total_probe_length); } + // Called whenever the table *might* need to conditionally grow. + // + // This function is an optimization opportunity to perform a rehash even when + // growth is unnecessary, because vacating tombstones is beneficial for + // performance in the long-run. void rehash_and_grow_if_necessary() { if (capacity_ == 0) { resize(1); @@ -1870,6 +2058,9 @@ class raw_hash_set { } protected: + // Attempts to find `key` in the table; if it isn't found, returns a slot that + // the value can be inserted into, with the control byte already set to + // `key`'s H2. template std::pair find_or_prepare_insert(const K& key) { prefetch_heap_block(); @@ -1890,6 +2081,10 @@ class raw_hash_set { return {prepare_insert(hash), true}; } + // Given the hash of a value not currently in the table, finds the next + // viable slot index to insert it at. + // + // REQUIRES: At least one non-full slot available. size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE { auto target = find_first_non_full(ctrl_, hash, capacity_); if (ABSL_PREDICT_FALSE(growth_left() == 0 && @@ -1933,12 +2128,22 @@ class raw_hash_set { growth_left() = CapacityToGrowth(capacity()) - size_; } + // The number of slots we can still fill without needing to rehash. + // + // This is stored separately due to tombstones: we do not include tombstones + // in the growth capacity, because we'd like to rehash when the table is + // otherwise filled with tombstones: otherwise, probe sequences might get + // unacceptably long without triggering a rehash. Callers can also force a + // rehash via the standard `rehash(0)`, which will recompute this value as a + // side-effect. + // + // See `CapacityToGrowth()`. size_t& growth_left() { return settings_.template get<0>(); } + // Prefetch the heap-allocated memory region to resolve potential TLB misses. + // This is intended to overlap with execution of calculating the hash for a + // key. void prefetch_heap_block() const { - // Prefetch the heap-allocated memory region to resolve potential TLB - // misses. This is intended to overlap with execution of calculating the - // hash for a key. #if defined(__GNUC__) __builtin_prefetch(static_cast(ctrl_), 0, 1); #endif // __GNUC__ @@ -1958,10 +2163,21 @@ class raw_hash_set { // TODO(alkis): Investigate removing some of these fields: // - ctrl/slots can be derived from each other // - size can be moved into the slot array - ctrl_t* ctrl_ = EmptyGroup(); // [(capacity + 1 + NumClonedBytes()) * ctrl_t] - slot_type* slots_ = nullptr; // [capacity * slot_type] - size_t size_ = 0; // number of full slots - size_t capacity_ = 0; // total number of slots + + // The control bytes (and, also, a pointer to the base of the backing array). + // + // This contains `capacity_ + 1 + NumClonedBytes()` entries, even + // when the table is empty (hence EmptyGroup). + ctrl_t* ctrl_ = EmptyGroup(); + // The beginning of the slots, located at `SlotOffset()` bytes after + // `ctrl_`. May be null for empty tables. + slot_type* slots_ = nullptr; + + // The number of filled slots. + size_t size_ = 0; + + // The total number of available slots. + size_t capacity_ = 0; absl::container_internal::CompressedTuple diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc index e0950b72..5bdd341e 100644 --- a/absl/debugging/internal/examine_stack.cc +++ b/absl/debugging/internal/examine_stack.cc @@ -20,7 +20,13 @@ #include #endif -#ifdef __APPLE__ +#include "absl/base/config.h" + +#ifdef ABSL_HAVE_MMAP +#include +#endif + +#if defined(__linux__) || defined(__APPLE__) #include #endif @@ -38,7 +44,102 @@ ABSL_NAMESPACE_BEGIN namespace debugging_internal { namespace { +constexpr int kDefaultDumpStackFramesLimit = 64; +// The %p field width for printf() functions is two characters per byte, +// and two extra for the leading "0x". +constexpr int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*); + ABSL_CONST_INIT SymbolizeUrlEmitter debug_stack_trace_hook = nullptr; + +// Async-signal safe mmap allocator. +void* Allocate(size_t num_bytes) { +#ifdef ABSL_HAVE_MMAP + void* p = ::mmap(nullptr, num_bytes, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + return p == MAP_FAILED ? nullptr : p; +#else + (void)num_bytes; + return nullptr; +#endif // ABSL_HAVE_MMAP +} + +void Deallocate(void* p, size_t size) { +#ifdef ABSL_HAVE_MMAP + ::munmap(p, size); +#else + (void)p; + (void)size; +#endif // ABSL_HAVE_MMAP +} + +// Print a program counter only. +void DumpPC(OutputWriter* writer, void* writer_arg, void* const pc, + const char* const prefix) { + char buf[100]; + snprintf(buf, sizeof(buf), "%s@ %*p\n", prefix, kPrintfPointerFieldWidth, pc); + writer(buf, writer_arg); +} + +// Print a program counter and the corresponding stack frame size. +void DumpPCAndFrameSize(OutputWriter* writer, void* writer_arg, void* const pc, + int framesize, const char* const prefix) { + char buf[100]; + if (framesize <= 0) { + snprintf(buf, sizeof(buf), "%s@ %*p (unknown)\n", prefix, + kPrintfPointerFieldWidth, pc); + } else { + snprintf(buf, sizeof(buf), "%s@ %*p %9d\n", prefix, + kPrintfPointerFieldWidth, pc, framesize); + } + writer(buf, writer_arg); +} + +// Print a program counter and the corresponding symbol. +void DumpPCAndSymbol(OutputWriter* writer, void* writer_arg, void* const pc, + const char* const prefix) { + char tmp[1024]; + const char* symbol = "(unknown)"; + // Symbolizes the previous address of pc because pc may be in the + // next function. The overrun happens when the function ends with + // a call to a function annotated noreturn (e.g. CHECK). + // If symbolization of pc-1 fails, also try pc on the off-chance + // that we crashed on the first instruction of a function (that + // actually happens very often for e.g. __restore_rt). + const uintptr_t prev_pc = reinterpret_cast(pc) - 1; + if (absl::Symbolize(reinterpret_cast(prev_pc), tmp, + sizeof(tmp)) || + absl::Symbolize(pc, tmp, sizeof(tmp))) { + symbol = tmp; + } + char buf[1024]; + snprintf(buf, sizeof(buf), "%s@ %*p %s\n", prefix, kPrintfPointerFieldWidth, + pc, symbol); + writer(buf, writer_arg); +} + +// Print a program counter, its stack frame size, and its symbol name. +// Note that there is a separate symbolize_pc argument. Return addresses may be +// at the end of the function, and this allows the caller to back up from pc if +// appropriate. +void DumpPCAndFrameSizeAndSymbol(OutputWriter* writer, void* writer_arg, + void* const pc, void* const symbolize_pc, + int framesize, const char* const prefix) { + char tmp[1024]; + const char* symbol = "(unknown)"; + if (absl::Symbolize(symbolize_pc, tmp, sizeof(tmp))) { + symbol = tmp; + } + char buf[1024]; + if (framesize <= 0) { + snprintf(buf, sizeof(buf), "%s@ %*p (unknown) %s\n", prefix, + kPrintfPointerFieldWidth, pc, symbol); + } else { + snprintf(buf, sizeof(buf), "%s@ %*p %9d %s\n", prefix, + kPrintfPointerFieldWidth, pc, framesize, symbol); + } + writer(buf, writer_arg); +} + } // namespace void RegisterDebugStackTraceHook(SymbolizeUrlEmitter hook) { @@ -50,7 +151,7 @@ SymbolizeUrlEmitter GetDebugStackTraceHook() { return debug_stack_trace_hook; } // Returns the program counter from signal context, nullptr if // unknown. vuc is a ucontext_t*. We use void* to avoid the use of // ucontext_t on non-POSIX systems. -void* GetProgramCounter(void* vuc) { +void* GetProgramCounter(void* const vuc) { #ifdef __linux__ if (vuc != nullptr) { ucontext_t* context = reinterpret_cast(vuc); @@ -132,60 +233,17 @@ void* GetProgramCounter(void* vuc) { return nullptr; } -// The %p field width for printf() functions is two characters per byte, -// and two extra for the leading "0x". -static constexpr int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*); - -// Print a program counter, its stack frame size, and its symbol name. -// Note that there is a separate symbolize_pc argument. Return addresses may be -// at the end of the function, and this allows the caller to back up from pc if -// appropriate. -static void DumpPCAndFrameSizeAndSymbol(void (*writerfn)(const char*, void*), - void* writerfn_arg, void* pc, - void* symbolize_pc, int framesize, - const char* const prefix) { - char tmp[1024]; - const char* symbol = "(unknown)"; - if (absl::Symbolize(symbolize_pc, tmp, sizeof(tmp)) || - (pc != symbolize_pc && absl::Symbolize(pc, tmp, sizeof(tmp)))) { - symbol = tmp; - } - char buf[1024]; - if (framesize <= 0) { - snprintf(buf, sizeof(buf), "%s@ %*p (unknown) %s\n", prefix, - kPrintfPointerFieldWidth, pc, symbol); - } else { - snprintf(buf, sizeof(buf), "%s@ %*p %9d %s\n", prefix, - kPrintfPointerFieldWidth, pc, framesize, symbol); - } - writerfn(buf, writerfn_arg); -} - -// Print a program counter and the corresponding stack frame size. -static void DumpPCAndFrameSize(void (*writerfn)(const char*, void*), - void* writerfn_arg, void* pc, int framesize, - const char* const prefix) { - char buf[100]; - if (framesize <= 0) { - snprintf(buf, sizeof(buf), "%s@ %*p (unknown)\n", prefix, - kPrintfPointerFieldWidth, pc); - } else { - snprintf(buf, sizeof(buf), "%s@ %*p %9d\n", prefix, - kPrintfPointerFieldWidth, pc, framesize); - } - writerfn(buf, writerfn_arg); -} - -void DumpPCAndFrameSizesAndStackTrace( - void* pc, void* const stack[], int frame_sizes[], int depth, - int min_dropped_frames, bool symbolize_stacktrace, - void (*writerfn)(const char*, void*), void* writerfn_arg) { +void DumpPCAndFrameSizesAndStackTrace(void* const pc, void* const stack[], + int frame_sizes[], int depth, + int min_dropped_frames, + bool symbolize_stacktrace, + OutputWriter* writer, void* writer_arg) { if (pc != nullptr) { // We don't know the stack frame size for PC, use 0. if (symbolize_stacktrace) { - DumpPCAndFrameSizeAndSymbol(writerfn, writerfn_arg, pc, pc, 0, "PC: "); + DumpPCAndFrameSizeAndSymbol(writer, writer_arg, pc, pc, 0, "PC: "); } else { - DumpPCAndFrameSize(writerfn, writerfn_arg, pc, 0, "PC: "); + DumpPCAndFrameSize(writer, writer_arg, pc, 0, "PC: "); } } for (int i = 0; i < depth; i++) { @@ -195,20 +253,61 @@ void DumpPCAndFrameSizesAndStackTrace( // call to a function annotated noreturn (e.g. CHECK). Note that we don't // do this for pc above, as the adjustment is only correct for return // addresses. - DumpPCAndFrameSizeAndSymbol(writerfn, writerfn_arg, stack[i], + DumpPCAndFrameSizeAndSymbol(writer, writer_arg, stack[i], reinterpret_cast(stack[i]) - 1, frame_sizes[i], " "); } else { - DumpPCAndFrameSize(writerfn, writerfn_arg, stack[i], frame_sizes[i], - " "); + DumpPCAndFrameSize(writer, writer_arg, stack[i], frame_sizes[i], " "); } } if (min_dropped_frames > 0) { char buf[100]; snprintf(buf, sizeof(buf), " @ ... and at least %d more frames\n", min_dropped_frames); - writerfn(buf, writerfn_arg); + writer(buf, writer_arg); + } +} + +// Dump current stack trace as directed by writer. +// Make sure this function is not inlined to avoid skipping too many top frames. +ABSL_ATTRIBUTE_NOINLINE +void DumpStackTrace(int min_dropped_frames, int max_num_frames, + bool symbolize_stacktrace, OutputWriter* writer, + void* writer_arg) { + // Print stack trace + void* stack_buf[kDefaultDumpStackFramesLimit]; + void** stack = stack_buf; + int num_stack = kDefaultDumpStackFramesLimit; + int allocated_bytes = 0; + + if (num_stack >= max_num_frames) { + // User requested fewer frames than we already have space for. + num_stack = max_num_frames; + } else { + const size_t needed_bytes = max_num_frames * sizeof(stack[0]); + void* p = Allocate(needed_bytes); + if (p != nullptr) { // We got the space. + num_stack = max_num_frames; + stack = reinterpret_cast(p); + allocated_bytes = needed_bytes; + } + } + + size_t depth = absl::GetStackTrace(stack, num_stack, min_dropped_frames + 1); + for (size_t i = 0; i < depth; i++) { + if (symbolize_stacktrace) { + DumpPCAndSymbol(writer, writer_arg, stack[i], " "); + } else { + DumpPC(writer, writer_arg, stack[i], " "); + } } + + auto hook = GetDebugStackTraceHook(); + if (hook != nullptr) { + (*hook)(stack, depth, writer, writer_arg); + } + + if (allocated_bytes != 0) Deallocate(stack, allocated_bytes); } } // namespace debugging_internal diff --git a/absl/debugging/internal/examine_stack.h b/absl/debugging/internal/examine_stack.h index 61f0056f..190af87f 100644 --- a/absl/debugging/internal/examine_stack.h +++ b/absl/debugging/internal/examine_stack.h @@ -31,7 +31,7 @@ typedef void OutputWriter(const char*, void*); // `hook` that is called each time DumpStackTrace() is called. // `hook` may be called from a signal handler. typedef void (*SymbolizeUrlEmitter)(void* const stack[], int depth, - OutputWriter writer, void* writer_arg); + OutputWriter* writer, void* writer_arg); // Registration of SymbolizeUrlEmitter for use inside of a signal handler. // This is inherently unsafe and must be signal safe code. @@ -41,14 +41,21 @@ SymbolizeUrlEmitter GetDebugStackTraceHook(); // Returns the program counter from signal context, or nullptr if // unknown. `vuc` is a ucontext_t*. We use void* to avoid the use of // ucontext_t on non-POSIX systems. -void* GetProgramCounter(void* vuc); +void* GetProgramCounter(void* const vuc); -// Uses `writerfn` to dump the program counter, stack trace, and stack +// Uses `writer` to dump the program counter, stack trace, and stack // frame sizes. -void DumpPCAndFrameSizesAndStackTrace( - void* pc, void* const stack[], int frame_sizes[], int depth, - int min_dropped_frames, bool symbolize_stacktrace, - void (*writerfn)(const char*, void*), void* writerfn_arg); +void DumpPCAndFrameSizesAndStackTrace(void* const pc, void* const stack[], + int frame_sizes[], int depth, + int min_dropped_frames, + bool symbolize_stacktrace, + OutputWriter* writer, void* writer_arg); + +// Dump current stack trace omitting the topmost `min_dropped_frames` stack +// frames. +void DumpStackTrace(int min_dropped_frames, int max_num_frames, + bool symbolize_stacktrace, OutputWriter* writer, + void* writer_arg); } // namespace debugging_internal ABSL_NAMESPACE_END -- cgit v1.2.3 From ca80034f59f43eddb6c4c72314572c0e212bf98f Mon Sep 17 00:00:00 2001 From: Calvin Ke Date: Sat, 26 Mar 2022 08:56:31 +0800 Subject: Support for QNX (#1147) --- absl/base/config.h | 3 ++- absl/debugging/failure_signal_handler.cc | 2 +- absl/debugging/internal/elf_mem_image.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'absl/debugging') diff --git a/absl/base/config.h b/absl/base/config.h index 8c100d8e..78de4d1c 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -414,7 +414,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || defined(_AIX) || defined(__ros__) || defined(__native_client__) || \ defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__) || \ defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \ - defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) + defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ + defined(__QNX__) #define ABSL_HAVE_MMAP 1 #endif diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index 689e5979..3fe8827a 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -52,7 +52,7 @@ #define ABSL_HAVE_SIGACTION // Apple WatchOS and TVOS don't allow sigaltstack #if !(defined(TARGET_OS_WATCH) && TARGET_OS_WATCH) && \ - !(defined(TARGET_OS_TV) && TARGET_OS_TV) + !(defined(TARGET_OS_TV) && TARGET_OS_TV) && !defined(__QNX__) #define ABSL_HAVE_SIGALTSTACK #endif #endif diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index be20256f..e4bbf2d7 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -31,7 +31,7 @@ #error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set #endif -#if defined(__ELF__) && !defined(__OpenBSD__) && \ +#if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \ !defined(__native_client__) && !defined(__asmjs__) && !defined(__wasm__) #define ABSL_HAVE_ELF_MEM_IMAGE 1 #endif -- cgit v1.2.3 From b9ad9bbfed92199a1a58504306d026cd2597539e Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Wed, 30 Mar 2022 21:56:20 +0200 Subject: Fix build with uclibc-ng (#1145) uclibc-ng doesn't provide getauxval which results in the following build failure on arm or ppc with any user of abseil-cpp such as grpc: /home/buildroot/autobuild/instance-0/output-1/host/opt/ext-toolchain/bin/../lib/gcc/arm-buildroot-linux-uclibcgnueabi/10.3.0/../../../../arm-buildroot-linux-uclibcgnueabi/bin/ld: /home/buildroot/autobuild/instance-0/output-1/host/arm-buildroot-linux-uclibcgnueabi/sysroot/usr/lib/libabsl_random_internal_randen_hwaes.so.2111.0.0: undefined reference to `getauxval' To fix this build failure, check that __UCLIBC__ is not defined before using getauxval (as Babel is not able to check function availability) Fixes: - http://autobuild.buildroot.org/results/775f3ca3dedebff29e212b29dfa896b7613b7a02 Signed-off-by: Fabrice Fontaine --- absl/debugging/internal/vdso_support.cc | 2 +- absl/random/internal/randen_detect.cc | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc index c655cf45..e63ac4a3 100644 --- a/absl/debugging/internal/vdso_support.cc +++ b/absl/debugging/internal/vdso_support.cc @@ -33,7 +33,7 @@ #endif #include -#if defined(__GLIBC__) && \ +#if !defined(__UCLIBC__) && defined(__GLIBC__) && \ (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16)) #define ABSL_HAVE_GETAUXVAL #endif diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc index 9bb58fc6..6dababa3 100644 --- a/absl/random/internal/randen_detect.cc +++ b/absl/random/internal/randen_detect.cc @@ -24,6 +24,11 @@ #include "absl/random/internal/platform.h" +#if !defined(__UCLIBC__) && defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16)) +#define ABSL_HAVE_GETAUXVAL +#endif + #if defined(ABSL_ARCH_X86_64) #define ABSL_INTERNAL_USE_X86_CPUID #elif defined(ABSL_ARCH_PPC) || defined(ABSL_ARCH_ARM) || \ @@ -31,7 +36,7 @@ #if defined(__ANDROID__) #define ABSL_INTERNAL_USE_ANDROID_GETAUXVAL #define ABSL_INTERNAL_USE_GETAUXVAL -#elif defined(__linux__) +#elif defined(__linux__) && defined(ABSL_HAVE_GETAUXVAL) #define ABSL_INTERNAL_USE_LINUX_GETAUXVAL #define ABSL_INTERNAL_USE_GETAUXVAL #endif -- cgit v1.2.3 From 6f43f5bb398b6685575b36874e36cf1695734df1 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 31 Mar 2022 17:42:13 -0700 Subject: Export of internal Abseil changes -- afa44fa0245a1cfb1824ef9697b3fa77fa9615c9 by Laramie Leavitt : Comment CMakeLists.txt about internal absl_cc_library() targets. From what I can tell, these are the CMake targets that are public: absl::algorithm absl::algorithm_container absl::base absl::core_headers absl::dynamic_annotations absl::log_severity absl::cleanup absl::btree absl::fixed_array absl::flat_hash_map absl::flat_hash_set absl::inlined_vector absl::node_hash_map absl::node_hash_set absl::debugging absl::failure_signal_handler absl::leak_check absl::leak_check_disable absl::stacktrace absl::symbolize absl::flags absl::flags_commandlineflag absl::flags_config absl::flags_marshalling absl::flags_parse absl::flags_reflection absl::flags_usage absl::bind_front absl::function_ref absl::hash absl::hash_testing absl::memory absl::meta absl::type_traits absl::bits absl::int128 absl::numeric absl::numeric_representation absl::exponential_biased absl::periodic_sampler absl::sample_recorder absl::random_bit_gen_ref absl::random_distributions absl::random_mocking_bit_gen absl::random_random absl::random_seed_gen_exception absl::random_seed_sequences absl::status absl::statusor absl::cord absl::cord_test_helpers absl::str_format absl::strings absl::synchronization absl::civil_time absl::time absl::time_zone absl::any absl::bad_any_cast absl::bad_optional_access absl::bad_variant_access absl::compare absl::optional absl::span absl::variant absl::utility PiperOrigin-RevId: 438702788 Change-Id: Icf611c35e88f03cd2493a95f61617605305d4e8e -- a99f60847578e6c0df6befadb29a01c86def0d21 by Abseil Team : Internal change PiperOrigin-RevId: 438647928 Change-Id: I141eadd17d6e8607df25ebc893aecefa0239a72f -- b23e77e8f62a77023188594390c9e491c507d22c by Abseil Team : Internal change PiperOrigin-RevId: 438628502 Change-Id: I40c4297716c8c1621ba8b02a22393bfcbefb5b5e GitOrigin-RevId: afa44fa0245a1cfb1824ef9697b3fa77fa9615c9 --- absl/base/CMakeLists.txt | 16 ++++++++++++++++ absl/cleanup/CMakeLists.txt | 1 + absl/container/BUILD.bazel | 29 +++++++++++------------------ absl/container/CMakeLists.txt | 27 +++++++++++++++++++++++++++ absl/debugging/CMakeLists.txt | 4 ++++ absl/hash/CMakeLists.txt | 3 +++ absl/strings/BUILD.bazel | 1 - absl/strings/CMakeLists.txt | 13 +++++++++++++ absl/synchronization/CMakeLists.txt | 4 ++++ absl/time/CMakeLists.txt | 1 + absl/types/CMakeLists.txt | 2 ++ 11 files changed, 82 insertions(+), 19 deletions(-) (limited to 'absl/debugging') diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index c7233cb3..7e600f0b 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -16,6 +16,7 @@ find_library(LIBRT rt) +# Internal-only target, do not depend on directly. absl_cc_library( NAME atomic_hook @@ -28,6 +29,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME errno_saver @@ -52,6 +54,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME raw_logging_internal @@ -68,6 +71,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME spinlock_wait @@ -131,6 +135,7 @@ absl_cc_library( PUBLIC ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME malloc_internal @@ -151,6 +156,7 @@ absl_cc_library( Threads::Threads ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME base_internal @@ -207,6 +213,7 @@ absl_cc_library( PUBLIC ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME throw_delegate @@ -221,6 +228,7 @@ absl_cc_library( absl::raw_logging_internal ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME exception_testing @@ -234,6 +242,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME pretty_function @@ -243,6 +252,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME exception_safety_testing @@ -276,6 +286,7 @@ absl_cc_test( GTest::gtest_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME atomic_hook_test_helper @@ -375,6 +386,7 @@ absl_cc_test( GTest::gtest_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME spinlock_test_common @@ -409,6 +421,7 @@ absl_cc_test( GTest::gtest_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME endian @@ -519,6 +532,7 @@ absl_cc_test( GTest::gtest_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME scoped_set_env @@ -570,6 +584,7 @@ absl_cc_test( GTest::gtest_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME strerror @@ -601,6 +616,7 @@ absl_cc_test( GTest::gtest_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME fast_type_id diff --git a/absl/cleanup/CMakeLists.txt b/absl/cleanup/CMakeLists.txt index 26a6d0dc..f5af40b4 100644 --- a/absl/cleanup/CMakeLists.txt +++ b/absl/cleanup/CMakeLists.txt @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Internal-only target, do not depend on directly. absl_cc_library( NAME cleanup_internal diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index 2095e57d..d733cb24 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -217,11 +217,6 @@ cc_test( ], ) -NOTEST_TAGS_NONMOBILE = [ - "no_test_darwin_x86_64", - "no_test_loonix", -] - NOTEST_TAGS_MOBILE = [ "no_test_android_arm", "no_test_android_arm64", @@ -229,8 +224,6 @@ NOTEST_TAGS_MOBILE = [ "no_test_ios_x86_64", ] -NOTEST_TAGS = NOTEST_TAGS_MOBILE + NOTEST_TAGS_NONMOBILE - cc_library( name = "flat_hash_map", hdrs = ["flat_hash_map.h"], @@ -251,7 +244,7 @@ cc_test( srcs = ["flat_hash_map_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS_NONMOBILE, + tags = ["no_test_loonix"], deps = [ ":flat_hash_map", ":hash_generator_testing", @@ -285,7 +278,7 @@ cc_test( srcs = ["flat_hash_set_test.cc"], copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"], linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS_NONMOBILE, + tags = ["no_test_loonix"], deps = [ ":flat_hash_set", ":hash_generator_testing", @@ -321,7 +314,7 @@ cc_test( srcs = ["node_hash_map_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS_NONMOBILE, + tags = ["no_test_loonix"], deps = [ ":hash_generator_testing", ":node_hash_map", @@ -354,7 +347,7 @@ cc_test( srcs = ["node_hash_set_test.cc"], copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"], linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS_NONMOBILE, + tags = ["no_test_loonix"], deps = [ ":node_hash_set", ":unordered_set_constructor_test", @@ -383,7 +376,7 @@ cc_test( srcs = ["internal/container_memory_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS_NONMOBILE, + tags = ["no_test_loonix"], deps = [ ":container_memory", ":test_instance_tracker", @@ -410,7 +403,7 @@ cc_test( srcs = ["internal/hash_function_defaults_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS, + tags = NOTEST_TAGS_MOBILE + ["no_test_loonix"], deps = [ ":hash_function_defaults", "//absl/hash", @@ -608,7 +601,7 @@ cc_test( srcs = ["internal/raw_hash_set_test.cc"], copts = ABSL_TEST_COPTS, linkstatic = 1, - tags = NOTEST_TAGS, + tags = NOTEST_TAGS_MOBILE + ["no_test_loonix"], deps = [ ":container_memory", ":hash_function_defaults", @@ -698,7 +691,7 @@ cc_test( srcs = ["internal/layout_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS, + tags = NOTEST_TAGS_MOBILE + ["no_test_loonix"], visibility = ["//visibility:private"], deps = [ ":layout", @@ -845,7 +838,7 @@ cc_test( srcs = ["internal/unordered_set_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS_NONMOBILE, + tags = ["no_test_loonix"], deps = [ ":unordered_set_constructor_test", ":unordered_set_lookup_test", @@ -860,7 +853,7 @@ cc_test( srcs = ["internal/unordered_map_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS_NONMOBILE, + tags = ["no_test_loonix"], deps = [ ":unordered_map_constructor_test", ":unordered_map_lookup_test", @@ -875,7 +868,7 @@ cc_test( srcs = ["sample_element_size_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - tags = NOTEST_TAGS_NONMOBILE, + tags = ["no_test_loonix"], visibility = ["//visibility:private"], deps = [ ":flat_hash_map", diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 7176907d..aad69fa2 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt @@ -42,6 +42,7 @@ absl_cc_library( absl::utility ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME btree_test_common @@ -84,6 +85,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME compressed_tuple @@ -162,6 +164,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME inlined_vector_internal @@ -194,6 +197,7 @@ absl_cc_library( PUBLIC ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME counting_allocator @@ -240,6 +244,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME test_instance_tracker @@ -411,6 +416,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME container_memory @@ -440,6 +446,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME hash_function_defaults @@ -472,6 +479,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME hash_generator_testing @@ -489,6 +497,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME hash_policy_testing @@ -514,6 +523,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME hash_policy_traits @@ -538,6 +548,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME hashtablez_sampler @@ -569,6 +580,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME hashtable_debug @@ -580,6 +592,7 @@ absl_cc_library( absl::hashtable_debug_hooks ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME hashtable_debug_hooks @@ -592,6 +605,7 @@ absl_cc_library( PUBLIC ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME node_slot_policy @@ -617,6 +631,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME raw_hash_map @@ -631,6 +646,7 @@ absl_cc_library( PUBLIC ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME container_common @@ -642,6 +658,7 @@ absl_cc_library( absl::type_traits ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME raw_hash_set @@ -704,6 +721,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME layout @@ -737,6 +755,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME tracked @@ -749,6 +768,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME unordered_map_constructor_test @@ -763,6 +783,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME unordered_map_lookup_test @@ -777,6 +798,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME unordered_map_members_test @@ -790,6 +812,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME unordered_map_modifiers_test @@ -804,6 +827,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME unordered_set_constructor_test @@ -818,6 +842,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME unordered_set_lookup_test @@ -832,6 +857,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME unordered_set_members_test @@ -845,6 +871,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME unordered_set_modifiers_test diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index b16fa007..5850bdd0 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -93,6 +93,7 @@ absl_cc_test( GTest::gmock ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME examine_stack @@ -147,6 +148,7 @@ absl_cc_test( GTest::gmock ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME debugging_internal @@ -168,6 +170,7 @@ absl_cc_library( absl::raw_logging_internal ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME demangle_internal @@ -298,6 +301,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME stack_consumption diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index 34434fa0..423b74b5 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt @@ -80,6 +80,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME spy_hash_state @@ -94,6 +95,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME city @@ -121,6 +123,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME low_level_hash diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 5f122ee9..813aef45 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -736,7 +736,6 @@ cc_test( "no_test_android_arm", "no_test_android_arm64", "no_test_android_x86", - "no_test_darwin_x86_64", "no_test_ios_x86_64", "no_test_loonix", "no_test_msvc_x64", diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 5d418c86..d8715ed1 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -68,6 +68,7 @@ absl_cc_library( PUBLIC ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME strings_internal @@ -385,6 +386,7 @@ absl_cc_library( PUBLIC ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME str_format_internal @@ -523,6 +525,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME pow10_helper @@ -550,6 +553,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cord_internal @@ -588,6 +592,7 @@ absl_cc_library( absl::type_traits ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cordz_update_tracker @@ -614,6 +619,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cordz_functions @@ -642,6 +648,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cordz_statistics @@ -656,6 +663,7 @@ absl_cc_library( absl::synchronization ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cordz_handle @@ -689,6 +697,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cordz_info @@ -756,6 +765,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cordz_sample_token @@ -794,6 +804,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cordz_update_scope @@ -859,6 +870,7 @@ absl_cc_library( PUBLIC ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cord_rep_test_util @@ -889,6 +901,7 @@ absl_cc_library( TESTONLY ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME cordz_test_helpers diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt index 605efe2d..9335c264 100644 --- a/absl/synchronization/CMakeLists.txt +++ b/absl/synchronization/CMakeLists.txt @@ -14,6 +14,7 @@ # limitations under the License. # +# Internal-only target, do not depend on directly. absl_cc_library( NAME graphcycles_internal @@ -32,6 +33,7 @@ absl_cc_library( absl::raw_logging_internal ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME kernel_timeout_internal @@ -125,6 +127,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME thread_pool @@ -170,6 +173,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME per_thread_sem_test_common diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt index f6ff8bd1..debab3ba 100644 --- a/absl/time/CMakeLists.txt +++ b/absl/time/CMakeLists.txt @@ -87,6 +87,7 @@ absl_cc_library( $<$:${CoreFoundation}> ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME time_internal_test_util diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index d7e8614e..830953ae 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt @@ -43,6 +43,7 @@ absl_cc_library( PUBLIC ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME bad_any_cast_impl @@ -239,6 +240,7 @@ absl_cc_test( GTest::gmock_main ) +# Internal-only target, do not depend on directly. absl_cc_library( NAME conformance_testing -- cgit v1.2.3 From 9fed77a6fea29b8c8468bd41c6259c7f67163a65 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 5 Apr 2022 13:00:39 -0700 Subject: Export of internal Abseil changes -- ef2bf829c333f378ecc12f3259e3187cdb75a3d5 by Abseil Team : debugging: fix the VDSO symbol name used for unwinding on RISC-V Linux The name listed in `man vdso` is incorrect. Instead, use the name from `linux-5.16/arch/riscv/kernel/vdso/rt_sigreturn.S` PiperOrigin-RevId: 439654174 Change-Id: Ib39d066f416681720068e806e828a2c76a14a532 -- 43dfad824afd36cfc3e5049b4fea71a2bccb066c by Benjamin Barenblat : Check printf format strings in str_format_convert_test Add ABSL_PRINTF_ATTRIBUTE to appropriate functions in strings/internal/str_format/convert_test. Correct TypedFormatConvertTest.Char, which was accidentally passing values of types larger than int to StrPrint. PiperOrigin-RevId: 439388148 Change-Id: I6cde4e8e0c6455064138192430f07f4c990be0bc -- f84b4ab2c3b070c8af0c82742ac7a8a4bf443bca by Derek Mauro : Use __builtin_memcmp in the absl::string_view implementation starting with MSVC 16.9, where it first appeared This enables more constexpr operations PiperOrigin-RevId: 439317316 Change-Id: Iaf1ce76b60901d4b2d5b96be5900c56572f57b15 GitOrigin-RevId: ef2bf829c333f378ecc12f3259e3187cdb75a3d5 --- absl/debugging/internal/stacktrace_riscv-inl.inc | 2 +- absl/strings/BUILD.bazel | 1 + absl/strings/CMakeLists.txt | 1 + absl/strings/internal/str_format/convert_test.cc | 34 +++++++++++++++++------- absl/strings/string_view.h | 5 ++-- 5 files changed, 30 insertions(+), 13 deletions(-) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/stacktrace_riscv-inl.inc b/absl/debugging/internal/stacktrace_riscv-inl.inc index b4bdb5f1..98b09a22 100644 --- a/absl/debugging/internal/stacktrace_riscv-inl.inc +++ b/absl/debugging/internal/stacktrace_riscv-inl.inc @@ -56,7 +56,7 @@ static const unsigned char *GetKernelRtSigreturnAddress() { absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info; // Symbol versioning pulled from arch/riscv/kernel/vdso/vdso.lds at v5.10. auto lookup = [&](int type) { - return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_4.15", type, + return vdso.LookupSymbol("__vdso_rt_sigreturn", "LINUX_4.15", type, &symbol_info); }; if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) || diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 813aef45..1cf58ca1 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -1191,6 +1191,7 @@ cc_test( deps = [ ":str_format_internal", ":strings", + "//absl/base:core_headers", "//absl/base:raw_logging_internal", "//absl/types:optional", "@com_google_googletest//:gtest_main", diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index d8715ed1..c4358a12 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -494,6 +494,7 @@ absl_cc_test( DEPS absl::strings absl::str_format_internal + absl::core_headers absl::raw_logging_internal absl::int128 GTest::gmock_main diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index d9fbf61c..300612b7 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc @@ -24,6 +24,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/attributes.h" #include "absl/base/internal/raw_logging.h" #include "absl/strings/internal/str_format/bind.h" #include "absl/strings/match.h" @@ -124,6 +125,7 @@ void StrAppendV(std::string *dst, const char *format, va_list ap) { delete[] buf; } +void StrAppend(std::string *, const char *, ...) ABSL_PRINTF_ATTRIBUTE(2, 3); void StrAppend(std::string *out, const char *format, ...) { va_list ap; va_start(ap, format); @@ -131,6 +133,7 @@ void StrAppend(std::string *out, const char *format, ...) { va_end(ap); } +std::string StrPrint(const char *, ...) ABSL_PRINTF_ATTRIBUTE(1, 2); std::string StrPrint(const char *format, ...) { va_list ap; va_start(ap, format); @@ -455,21 +458,32 @@ TYPED_TEST_P(TypedFormatConvertTest, AllIntsWithFlags) { } TYPED_TEST_P(TypedFormatConvertTest, Char) { + // Pass a bunch of values of type TypeParam to both FormatPack and libc's + // vsnprintf("%c", ...) (wrapped in StrPrint) to make sure we get the same + // value. typedef TypeParam T; using remove_volatile_t = typename std::remove_volatile::type; - static const T kMin = std::numeric_limits::min(); - static const T kMax = std::numeric_limits::max(); - T kVals[] = { - remove_volatile_t(1), remove_volatile_t(2), remove_volatile_t(10), - remove_volatile_t(-1), remove_volatile_t(-2), remove_volatile_t(-10), - remove_volatile_t(0), - kMin + remove_volatile_t(1), kMin, - kMax - remove_volatile_t(1), kMax + std::vector vals = { + remove_volatile_t(1), remove_volatile_t(2), remove_volatile_t(10), // + remove_volatile_t(-1), remove_volatile_t(-2), remove_volatile_t(-10), // + remove_volatile_t(0), }; - for (const T &c : kVals) { + + // We'd like to test values near std::numeric_limits::min() and + // std::numeric_limits::max(), too, but vsnprintf("%c", ...) can't handle + // anything larger than an int. Add in the most extreme values we can without + // exceeding that range. + static const T kMin = + static_cast(std::numeric_limits::min()); + static const T kMax = + static_cast(std::numeric_limits::max()); + vals.insert(vals.end(), {kMin + 1, kMin, kMax - 1, kMax}); + + for (const T c : vals) { const FormatArgImpl args[] = {FormatArgImpl(c)}; UntypedFormatSpecImpl format("%c"); - EXPECT_EQ(StrPrint("%c", c), FormatPack(format, absl::MakeSpan(args))); + EXPECT_EQ(StrPrint("%c", static_cast(c)), + FormatPack(format, absl::MakeSpan(args))); } } diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index a4c9a652..e3239f57 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h @@ -55,8 +55,9 @@ ABSL_NAMESPACE_END #else // ABSL_USES_STD_STRING_VIEW -#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \ - (defined(__GNUC__) && !defined(__clang__)) +#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \ + (defined(__GNUC__) && !defined(__clang__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1928) #define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp #else // ABSL_HAVE_BUILTIN(__builtin_memcmp) #define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp -- cgit v1.2.3 From ac1398a6296de03413d7b88df4b4aa16e9e450cc Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 12 Apr 2022 09:04:16 -0700 Subject: Export of internal Abseil changes -- f4c7e510922668c68be4aa79a00867c3d3ca9f95 by Derek Mauro : Many improvements to LeakChecker builds The presence of the LeakChecker is now detected when possible. GCC users using LeakChecker in standalone mode still need to use -DLEAK_CHECKER. This is now documented in the header. The hacky targets used for testing leak checking have been removed in favor of testing in AddressSanitizer mode on Kokoro. Fixes #885 Fixes #1153 PiperOrigin-RevId: 441203393 Change-Id: Ibe64ef6b104bcaf31839ff7184e558cc86abdd1c -- 5c70a23aa83b8152ab95d2cf21662fc63c80ef7d by Abseil Team : Add a benchmark for stacktrace PiperOrigin-RevId: 441196473 Change-Id: I4c9aa2e797aa2cae09abfaaee3abe5c09eb62fc4 -- 50b406052273b9d5bad04a7860a96e4d5d956c02 by Abseil Team : Internal change. PiperOrigin-RevId: 441114481 Change-Id: I667af7a50d5631ca91289dd24c91ba90233e0184 -- 568b4eaac120b420bce5290179d407d2b57d5bae by Dino Radakovic : Internal change PiperOrigin-RevId: 440894155 Change-Id: Ia587ffc65a8321126585fb363b7c0ca8cc2a0da2 -- d53948eace4f3a10ac5a6c1496dc51b81adc412c by Abseil Team : Explicitly give internal linkage to symbols which are not used outside of their translation units. PiperOrigin-RevId: 440424519 Change-Id: I531c5e229d443375483b7550a34f48042589a99b GitOrigin-RevId: f4c7e510922668c68be4aa79a00867c3d3ca9f95 --- CMake/AbseilDll.cmake | 3 +- absl/base/config.h | 17 ++++ absl/base/internal/sysinfo.cc | 1 - absl/copts/AbseilConfigureCopts.cmake | 10 -- absl/debugging/BUILD.bazel | 113 ++++++--------------- absl/debugging/CMakeLists.txt | 72 +------------ absl/debugging/leak_check.cc | 44 ++++---- absl/debugging/leak_check.h | 19 +++- absl/debugging/leak_check_disable.cc | 20 ---- absl/debugging/leak_check_test.cc | 17 ++-- absl/debugging/stacktrace_benchmark.cc | 55 ++++++++++ absl/flags/flag_test.cc | 6 +- absl/flags/internal/usage_test.cc | 6 +- absl/hash/internal/city_test.cc | 2 + absl/profiling/internal/exponential_biased_test.cc | 2 + absl/strings/str_format_test.cc | 2 + absl/synchronization/BUILD.bazel | 6 +- absl/time/internal/cctz/BUILD.bazel | 6 +- 18 files changed, 178 insertions(+), 223 deletions(-) delete mode 100644 absl/debugging/leak_check_disable.cc create mode 100644 absl/debugging/stacktrace_benchmark.cc (limited to 'absl/debugging') diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 518c469b..4f7a287c 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -90,7 +90,6 @@ set(ABSL_INTERNAL_DLL_FILES "debugging/failure_signal_handler.cc" "debugging/failure_signal_handler.h" "debugging/leak_check.h" - "debugging/leak_check_disable.cc" "debugging/stacktrace.cc" "debugging/stacktrace.h" "debugging/symbolize.cc" @@ -345,6 +344,7 @@ set(ABSL_INTERNAL_DLL_FILES "types/internal/span.h" "types/variant.h" "utility/utility.h" + "debugging/leak_check.cc" ) set(ABSL_INTERNAL_DLL_TARGETS @@ -355,7 +355,6 @@ set(ABSL_INTERNAL_DLL_TARGETS "debugging_internal" "demangle_internal" "leak_check" - "leak_check_disable" "stack_consumption" "debugging" "hash" diff --git a/absl/base/config.h b/absl/base/config.h index 429dd353..3f5ace3f 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -797,10 +797,27 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // ABSL_HAVE_LEAK_SANITIZER // // LeakSanitizer (or lsan) is a detector of memory leaks. +// https://clang.llvm.org/docs/LeakSanitizer.html +// https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer +// +// The macro ABSL_HAVE_LEAK_SANITIZER can be used to detect at compile-time +// whether the LeakSanitizer is potentially available. However, just because the +// LeakSanitizer is available does not mean it is active. Use the +// always-available run-time interface in //absl/debugging/leak_check.h for +// interacting with LeakSanitizer. #ifdef ABSL_HAVE_LEAK_SANITIZER #error "ABSL_HAVE_LEAK_SANITIZER cannot be directly set." +#elif defined(LEAK_SANITIZER) +// GCC provides no method for detecting the presense of the standalone +// LeakSanitizer (-fsanitize=leak), so GCC users of -fsanitize=leak should also +// use -DLEAK_SANITIZER. +#define ABSL_HAVE_LEAK_SANITIZER 1 +// Clang standalone LeakSanitizer (-fsanitize=leak) #elif ABSL_HAVE_FEATURE(leak_sanitizer) #define ABSL_HAVE_LEAK_SANITIZER 1 +#elif defined(ABSL_HAVE_ADDRESS_SANITIZER) +// GCC or Clang using the LeakSanitizer integrated into AddressSanitizer. +#define ABSL_HAVE_LEAK_SANITIZER 1 #endif // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index a7cfb461..c8366df1 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc @@ -124,7 +124,6 @@ int Win32NumCPUs() { } // namespace - static int GetNumCPUs() { #if defined(__myriad2__) return 1; diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake index 15d6c895..73435e99 100644 --- a/absl/copts/AbseilConfigureCopts.cmake +++ b/absl/copts/AbseilConfigureCopts.cmake @@ -1,8 +1,6 @@ # See absl/copts/copts.py and absl/copts/generate_copts.py include(GENERATED_AbseilCopts) -set(ABSL_LSAN_LINKOPTS "") -set(ABSL_HAVE_LSAN OFF) set(ABSL_DEFAULT_LINKOPTS "") if (BUILD_SHARED_LIBS AND MSVC) @@ -85,14 +83,6 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # MATCHES so we get both Clang an else() set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}") - if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - # AppleClang doesn't have lsan - # https://developer.apple.com/documentation/code_diagnostics - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) - set(ABSL_LSAN_LINKOPTS "-fsanitize=leak") - set(ABSL_HAVE_LSAN ON) - endif() - endif() endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}") diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index 3c4ea8dc..7f5c1cad 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -225,6 +225,7 @@ cc_library( name = "leak_check", srcs = ["leak_check.cc"], hdrs = ["leak_check.h"], + copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:config", @@ -232,98 +233,33 @@ cc_library( ], ) -# Adding a dependency to leak_check_disable will disable -# sanitizer leak checking (asan/lsan) in a test without -# the need to mess around with build features. -cc_library( - name = "leak_check_disable", - srcs = ["leak_check_disable.cc"], - linkopts = ABSL_DEFAULT_LINKOPTS, - linkstatic = 1, - deps = ["//absl/base:config"], - alwayslink = 1, -) - -# These targets exists for use in tests only, explicitly configuring the -# LEAK_SANITIZER macro. It must be linked with -fsanitize=leak for lsan. -ABSL_LSAN_LINKOPTS = select({ - "//absl:clang_compiler": ["-fsanitize=leak"], - "//conditions:default": [], -}) - -cc_library( - name = "leak_check_api_enabled_for_testing", - testonly = 1, - srcs = ["leak_check.cc"], - hdrs = ["leak_check.h"], - copts = select({ - "//absl:clang_compiler": ["-DLEAK_SANITIZER"], - "//conditions:default": [], - }), - linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = ["//visibility:private"], - deps = [ - "//absl/base:config", - "//absl/base:core_headers", - ], -) - -cc_library( - name = "leak_check_api_disabled_for_testing", - testonly = 1, - srcs = ["leak_check.cc"], - hdrs = ["leak_check.h"], - copts = ["-ULEAK_SANITIZER"], - linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = ["//visibility:private"], - deps = [ - "//absl/base:config", - "//absl/base:core_headers", - ], -) - cc_test( name = "leak_check_test", srcs = ["leak_check_test.cc"], - copts = select({ - "//absl:clang_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"], - "//conditions:default": [], - }), - linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS, - tags = ["notsan"], - deps = [ - ":leak_check_api_enabled_for_testing", - "//absl/base", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "leak_check_no_lsan_test", - srcs = ["leak_check_test.cc"], - copts = ["-UABSL_EXPECT_LEAK_SANITIZER"], + copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - tags = ["noasan"], + tags = ["notsan"], deps = [ - ":leak_check_api_disabled_for_testing", - "//absl/base", # for raw_logging + ":leak_check", + "//absl/base:config", + "//absl/base:raw_logging_internal", "@com_google_googletest//:gtest_main", ], ) -# Test that leak checking is skipped when lsan is enabled but -# ":leak_check_disable" is linked in. -# -# This test should fail in the absence of a dependency on ":leak_check_disable" -cc_test( - name = "disabled_leak_check_test", +# Binary that leaks memory and expects to fail on exit. This isn't a +# test that expected to pass on its own; it exists to be called by a +# script that checks exit status and output. +# TODO(absl-team): Write a test to run this with a script that +# verifies that it correctly fails. +cc_binary( + name = "leak_check_fail_test_binary", srcs = ["leak_check_fail_test.cc"], - linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS, - tags = ["notsan"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ - ":leak_check_api_enabled_for_testing", - ":leak_check_disable", - "//absl/base", + ":leak_check", + "//absl/base:raw_logging_internal", "@com_google_googletest//:gtest_main", ], ) @@ -356,3 +292,18 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_binary( + name = "stacktrace_benchmark", + testonly = 1, + srcs = ["stacktrace_benchmark.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + tags = ["benchmark"], + deps = [ + ":stacktrace", + "//absl/base:config", + "//absl/base:core_headers", + "@com_github_google_benchmark//:benchmark_main", + ], +) diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index 5850bdd0..7507ff3b 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -218,42 +218,6 @@ absl_cc_library( PUBLIC ) -absl_cc_library( - NAME - leak_check_disable - SRCS - "leak_check_disable.cc" - COPTS - ${ABSL_DEFAULT_COPTS} - PUBLIC -) - -absl_cc_library( - NAME - leak_check_api_enabled_for_testing - HDRS - "leak_check.h" - SRCS - "leak_check.cc" - COPTS - ${ABSL_DEFAULT_COPTS} - $<$:-DLEAK_SANITIZER> - TESTONLY -) - -absl_cc_library( - NAME - leak_check_api_disabled_for_testing - HDRS - "leak_check.h" - SRCS - "leak_check.cc" - COPTS - ${ABSL_DEFAULT_COPTS} - "-ULEAK_SANITIZER" - TESTONLY -) - absl_cc_test( NAME leak_check_test @@ -261,43 +225,11 @@ absl_cc_test( "leak_check_test.cc" COPTS ${ABSL_TEST_COPTS} - "$<$:-DABSL_EXPECT_LEAK_SANITIZER>" LINKOPTS - "${ABSL_LSAN_LINKOPTS}" - DEPS - absl::leak_check_api_enabled_for_testing - absl::base - GTest::gmock_main -) - -absl_cc_test( - NAME - leak_check_no_lsan_test - SRCS - "leak_check_test.cc" - COPTS - ${ABSL_TEST_COPTS} - "-UABSL_EXPECT_LEAK_SANITIZER" - DEPS - absl::leak_check_api_disabled_for_testing - absl::base - GTest::gmock_main -) - -absl_cc_test( - NAME - disabled_leak_check_test - SRCS - "leak_check_fail_test.cc" - COPTS - ${ABSL_TEST_COPTS} - LINKOPTS - "${ABSL_LSAN_LINKOPTS}" + ${ABSL_DEFAULT_LINKOPTS} DEPS - absl::leak_check_api_enabled_for_testing - absl::leak_check_disable + absl::leak_check absl::base - absl::raw_logging_internal GTest::gmock_main ) diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc index 764ca0ad..195e82bf 100644 --- a/absl/debugging/leak_check.cc +++ b/absl/debugging/leak_check.cc @@ -11,29 +11,19 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - +// // Wrappers around lsan_interface functions. -// When lsan is not linked in, these functions are not available, -// therefore Abseil code which depends on these functions is conditioned on the -// definition of LEAK_SANITIZER. -#include "absl/base/attributes.h" -#include "absl/debugging/leak_check.h" +// +// These are always-available run-time functions manipulating the LeakSanitizer, +// even when the lsan_interface (and LeakSanitizer) is not available. When +// LeakSanitizer is not linked in, these functions become no-op stubs. -#ifndef LEAK_SANITIZER +#include "absl/debugging/leak_check.h" -namespace absl { -ABSL_NAMESPACE_BEGIN -bool HaveLeakSanitizer() { return false; } -bool LeakCheckerIsActive() { return false; } -void DoIgnoreLeak(const void*) { } -void RegisterLivePointers(const void*, size_t) { } -void UnRegisterLivePointers(const void*, size_t) { } -LeakCheckDisabler::LeakCheckDisabler() { } -LeakCheckDisabler::~LeakCheckDisabler() { } -ABSL_NAMESPACE_END -} // namespace absl +#include "absl/base/attributes.h" +#include "absl/base/config.h" -#else +#if defined(ABSL_HAVE_LEAK_SANITIZER) #include @@ -66,4 +56,18 @@ LeakCheckDisabler::~LeakCheckDisabler() { __lsan_enable(); } ABSL_NAMESPACE_END } // namespace absl -#endif // LEAK_SANITIZER +#else // defined(ABSL_HAVE_LEAK_SANITIZER) + +namespace absl { +ABSL_NAMESPACE_BEGIN +bool HaveLeakSanitizer() { return false; } +bool LeakCheckerIsActive() { return false; } +void DoIgnoreLeak(const void*) { } +void RegisterLivePointers(const void*, size_t) { } +void UnRegisterLivePointers(const void*, size_t) { } +LeakCheckDisabler::LeakCheckDisabler() { } +LeakCheckDisabler::~LeakCheckDisabler() { } +ABSL_NAMESPACE_END +} // namespace absl + +#endif // defined(ABSL_HAVE_LEAK_SANITIZER) diff --git a/absl/debugging/leak_check.h b/absl/debugging/leak_check.h index 5fc2b052..eff162f6 100644 --- a/absl/debugging/leak_check.h +++ b/absl/debugging/leak_check.h @@ -24,7 +24,24 @@ // Note: this leak checking API is not yet supported in MSVC. // Leak checking is enabled by default in all ASan builds. // -// See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer +// https://clang.llvm.org/docs/LeakSanitizer.html +// https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer +// +// GCC and Clang both automatically enable LeakSanitizer when AddressSanitizer +// is enabled. To use the mode, simply pass `-fsanitize=address` to both the +// compiler and linker. An example Bazel command could be +// +// $ bazel test --copt=-fsanitize=address --linkopt=-fsanitize=address ... +// +// GCC and Clang auto support a standalone LeakSanitizer mode (a mode which does +// not also use AddressSanitizer). To use the mode, simply pass +// `-fsanitize=leak` to both the compiler and linker. Since GCC does not +// currently provide a way of detecting this mode at compile-time, GCC users +// must also pass -DLEAK_SANIITIZER to the compiler. An example Bazel command +// could be +// +// $ bazel test --copt=-DLEAK_SANITIZER --copt=-fsanitize=leak +// --linkopt=-fsanitize=leak ... // // ----------------------------------------------------------------------------- #ifndef ABSL_DEBUGGING_LEAK_CHECK_H_ diff --git a/absl/debugging/leak_check_disable.cc b/absl/debugging/leak_check_disable.cc deleted file mode 100644 index 924d6e3d..00000000 --- a/absl/debugging/leak_check_disable.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Disable LeakSanitizer when this file is linked in. -// This function overrides __lsan_is_turned_off from sanitizer/lsan_interface.h -extern "C" int __lsan_is_turned_off(); -extern "C" int __lsan_is_turned_off() { - return 1; -} diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc index 9fcfc8e5..6a42e31b 100644 --- a/absl/debugging/leak_check_test.cc +++ b/absl/debugging/leak_check_test.cc @@ -15,27 +15,24 @@ #include #include "gtest/gtest.h" +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/debugging/leak_check.h" namespace { -TEST(LeakCheckTest, DetectLeakSanitizer) { -#ifdef ABSL_EXPECT_LEAK_SANITIZER - EXPECT_TRUE(absl::HaveLeakSanitizer()); - EXPECT_TRUE(absl::LeakCheckerIsActive()); -#else - EXPECT_FALSE(absl::HaveLeakSanitizer()); - EXPECT_FALSE(absl::LeakCheckerIsActive()); -#endif -} - TEST(LeakCheckTest, IgnoreLeakSuppressesLeakedMemoryErrors) { + if (!absl::LeakCheckerIsActive()) { + GTEST_SKIP() << "LeakChecker is not active"; + } auto foo = absl::IgnoreLeak(new std::string("some ignored leaked string")); ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str()); } TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) { + if (!absl::LeakCheckerIsActive()) { + GTEST_SKIP() << "LeakChecker is not active"; + } absl::LeakCheckDisabler disabler; auto foo = new std::string("some string leaked while checks are disabled"); ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str()); diff --git a/absl/debugging/stacktrace_benchmark.cc b/absl/debugging/stacktrace_benchmark.cc new file mode 100644 index 00000000..9360bafe --- /dev/null +++ b/absl/debugging/stacktrace_benchmark.cc @@ -0,0 +1,55 @@ +// Copyright 2022 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/base/optimization.h" +#include "absl/debugging/stacktrace.h" +#include "benchmark/benchmark.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace { + +static constexpr int kMaxStackDepth = 100; +static constexpr int kCacheSize = (1 << 16); +void* pcs[kMaxStackDepth]; + +ABSL_ATTRIBUTE_NOINLINE void func(benchmark::State& state, int x, int depth) { + if (x <= 0) { + // Touch a significant amount of memory so that the stack is likely to be + // not cached in the L1 cache. + state.PauseTiming(); + int* arr = new int[kCacheSize]; + for (int i = 0; i < kCacheSize; ++i) benchmark::DoNotOptimize(arr[i] = 100); + delete[] arr; + state.ResumeTiming(); + benchmark::DoNotOptimize(absl::GetStackTrace(pcs, depth, 0)); + return; + } + ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); + func(state, --x, depth); +} + +void BM_GetStackTrace(benchmark::State& state) { + int depth = state.range(0); + for (auto s : state) { + func(state, depth, depth); + } +} + +BENCHMARK(BM_GetStackTrace)->DenseRange(10, kMaxStackDepth, 10); +} // namespace +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 05ec79e8..845b4eba 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -854,7 +854,9 @@ ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr"); ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr"); ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr")); -bool initializaion_order_fiasco_test = [] { +namespace { + +bool initialization_order_fiasco_test ABSL_ATTRIBUTE_UNUSED = [] { // Iterate over all the flags during static initialization. // This should not trigger ASan's initialization-order-fiasco. auto* handle1 = absl::FindCommandLineFlag("flag_on_separate_file"); @@ -865,8 +867,6 @@ bool initializaion_order_fiasco_test = [] { return true; }(); -namespace { - TEST_F(FlagTest, TestRetiredFlagRegistration) { auto* handle = absl::FindCommandLineFlag("old_bool_flag"); EXPECT_TRUE(handle->IsOfType()); diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc index 044d71c8..6a65a1a3 100644 --- a/absl/flags/internal/usage_test.cc +++ b/absl/flags/internal/usage_test.cc @@ -47,8 +47,10 @@ struct UDT { UDT(const UDT&) = default; UDT& operator=(const UDT&) = default; }; -bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; } -std::string AbslUnparseFlag(const UDT&) { return "UDT{}"; } +static bool AbslParseFlag(absl::string_view, UDT*, std::string*) { + return true; +} +static std::string AbslUnparseFlag(const UDT&) { return "UDT{}"; } ABSL_FLAG(UDT, usage_reporting_test_flag_05, {}, "usage_reporting_test_flag_05 help message"); diff --git a/absl/hash/internal/city_test.cc b/absl/hash/internal/city_test.cc index 251d381d..1bbf02e0 100644 --- a/absl/hash/internal/city_test.cc +++ b/absl/hash/internal/city_test.cc @@ -22,6 +22,7 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace hash_internal { +namespace { static const uint64_t k0 = 0xc3a5c85c97cb3127ULL; static const uint64_t kSeed0 = 1234567; @@ -590,6 +591,7 @@ TEST(CityHashTest, Unchanging) { TestUnchanging(testdata[i], 0, kDataSize); } +} // namespace } // namespace hash_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/profiling/internal/exponential_biased_test.cc b/absl/profiling/internal/exponential_biased_test.cc index 5675001d..6a6c317e 100644 --- a/absl/profiling/internal/exponential_biased_test.cc +++ b/absl/profiling/internal/exponential_biased_test.cc @@ -29,6 +29,7 @@ using ::testing::Ge; namespace absl { ABSL_NAMESPACE_BEGIN namespace profiling_internal { +namespace { MATCHER_P2(IsBetween, a, b, absl::StrCat(std::string(negation ? "isn't" : "is"), " between ", a, @@ -194,6 +195,7 @@ TEST(ExponentialBiasedTest, InitializationModes) { EXPECT_THAT(eb_stack.GetSkipCount(2), Ge(0)); } +} // namespace } // namespace profiling_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index c60027ad..804e6c22 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc @@ -719,6 +719,7 @@ TEST_F(FormatWrapperTest, ParsedFormat) { ABSL_NAMESPACE_END } // namespace absl +namespace { using FormatExtensionTest = ::testing::Test; struct Point { @@ -750,6 +751,7 @@ TEST_F(FormatExtensionTest, AbslFormatConvertExample) { // FormatUntyped will return false for bad character. EXPECT_FALSE(absl::FormatUntyped(&actual, f1, {absl::FormatArg(p)})); } +} // namespace // Some codegen thunks that we can use to easily dump the generated assembly for // different StrFormat calls. diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index a0492c55..4e175892 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel @@ -97,8 +97,8 @@ cc_library( deps = [ ":graphcycles_internal", ":kernel_timeout_internal", - "//absl/base", "//absl/base:atomic_hook", + "//absl/base", "//absl/base:base_internal", "//absl/base:config", "//absl/base:core_headers", @@ -108,7 +108,9 @@ cc_library( "//absl/debugging:stacktrace", "//absl/debugging:symbolize", "//absl/time", - ], + ] + select({ + "//conditions:default": [], + }), ) cc_test( diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel index bdc2e309..f0e7ae13 100644 --- a/absl/time/internal/cctz/BUILD.bazel +++ b/absl/time/internal/cctz/BUILD.bazel @@ -85,7 +85,11 @@ cc_library( deps = [ ":civil_time", "//absl/base:config", - ], + ] + select( + { + "//conditions:default": [], + }, + ), ) ### tests -- cgit v1.2.3 From c27ab06897f330267bed99061ed3e523e2606bf1 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 15 Apr 2022 10:12:39 -0700 Subject: Export of internal Abseil changes -- 3d018c03a34bf273a4b24b3584ed77f0a6d21686 by Abseil Team : Fix a spelling typo (s/boundries/boundaries). PiperOrigin-RevId: 442041877 Change-Id: I608020697d37b85316bb9a0838e4b457659c926c -- 518b8119e51db24ce7fb0fd2fe537ec43825c3e6 by Dino Radakovic : absl/types/internal/variant: Make include guard uppercase https://google.github.io/styleguide/cppguide.html#The__define_Guard PiperOrigin-RevId: 441911692 Change-Id: I9837dd07f20204d8253f20627b0917a34dc21825 -- b91696c38310a7cae8c1ea9e2d479495f5dc3f69 by Greg Falcon : Add an internal-only API to wrap __builtin_prefetch() if available. This private API is intended for future use by the Abseil implementation. Like any internal-namespaced function, it may be changed or removed at any time. PiperOrigin-RevId: 441894616 Change-Id: Iaa48bd4680b373f4a0d5afab0cb35e2a1908595f -- 0f01e8b0551a662e02dff60840c54320f987315f by Derek Mauro : C++20: Use the standard `constinit` keyword for `ABSL_CONST_INIT` when available PiperOrigin-RevId: 441778874 Change-Id: I70c616469752ff23b326b1c615437599f42cc6aa GitOrigin-RevId: 3d018c03a34bf273a4b24b3584ed77f0a6d21686 --- CMake/AbseilDll.cmake | 1 + absl/base/BUILD.bazel | 25 ++++++++ absl/base/CMakeLists.txt | 26 ++++++++ absl/base/attributes.h | 26 ++++++-- absl/base/internal/prefetch.h | 109 ++++++++++++++++++++++++++++++++ absl/base/internal/prefetch_test.cc | 43 +++++++++++++ absl/container/flat_hash_map.h | 2 +- absl/container/flat_hash_set.h | 2 +- absl/container/node_hash_map.h | 2 +- absl/container/node_hash_set.h | 2 +- absl/debugging/internal/vdso_support.cc | 4 +- absl/strings/internal/cord_internal.h | 3 +- absl/strings/internal/escaping.cc | 2 +- absl/strings/numbers.cc | 16 ++--- absl/types/internal/variant.h | 6 +- 15 files changed, 245 insertions(+), 24 deletions(-) create mode 100644 absl/base/internal/prefetch.h create mode 100644 absl/base/internal/prefetch_test.cc (limited to 'absl/debugging') diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 4f7a287c..0b5f0a54 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -26,6 +26,7 @@ set(ABSL_INTERNAL_DLL_FILES "base/internal/low_level_alloc.h" "base/internal/low_level_scheduling.h" "base/internal/per_thread_tls.h" + "base/internal/prefetch.h" "base/internal/pretty_function.h" "base/internal/raw_logging.cc" "base/internal/raw_logging.h" diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 6f2f09b9..49e3a95f 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -704,6 +704,31 @@ cc_test( ], ) +cc_library( + name = "prefetch", + hdrs = ["internal/prefetch.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = [ + "//absl:__subpackages__", + ], + deps = [ + ":config", + ], +) + +cc_test( + name = "prefetch_test", + size = "small", + srcs = ["internal/prefetch_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":prefetch", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "unique_small_name_test", size = "small", diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 7e600f0b..0e1e0413 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -642,6 +642,32 @@ absl_cc_test( GTest::gtest_main ) +# Internal-only target, do not depend on directly. +absl_cc_library( + NAME + prefetch + HDRS + "internal/prefetch.h" + COPTS + ${ABSL_DEFAULT_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::config +) + +absl_cc_test( + NAME + prefetch_test + SRCS + "internal/prefetch_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::prefetch + GTest::gtest_main +) + absl_cc_test( NAME optimization_test diff --git a/absl/base/attributes.h b/absl/base/attributes.h index c71038c7..e4e7a3d8 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -682,9 +682,18 @@ // not compile (on supported platforms) unless the variable has a constant // initializer. This is useful for variables with static and thread storage // duration, because it guarantees that they will not suffer from the so-called -// "static init order fiasco". Prefer to put this attribute on the most visible -// declaration of the variable, if there's more than one, because code that -// accesses the variable can then use the attribute for optimization. +// "static init order fiasco". +// +// This attribute must be placed on the initializing declaration of the +// variable. Some compilers will give a -Wmissing-constinit warning when this +// attribute is placed on some other declaration but missing from the +// initializing declaration. +// +// In some cases (notably with thread_local variables), `ABSL_CONST_INIT` can +// also be used in a non-initializing declaration to tell the compiler that a +// variable is already initialized, reducing overhead that would otherwise be +// incurred by a hidden guard variable. Thus annotating all declarations with +// this attribute is recommended to potentially enhance optimization. // // Example: // @@ -693,14 +702,19 @@ // ABSL_CONST_INIT static MyType my_var; // }; // -// MyType MyClass::my_var = MakeMyType(...); +// ABSL_CONST_INIT MyType MyClass::my_var = MakeMyType(...); +// +// For code or headers that are assured to only build with C++20 and up, prefer +// just using the standard `constinit` keyword directly over this macro. // // Note that this attribute is redundant if the variable is declared constexpr. -#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) +#if defined(__cpp_constinit) && __cpp_constinit >= 201907L +#define ABSL_CONST_INIT constinit +#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) #define ABSL_CONST_INIT [[clang::require_constant_initialization]] #else #define ABSL_CONST_INIT -#endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) +#endif // ABSL_ATTRIBUTE_PURE_FUNCTION // diff --git a/absl/base/internal/prefetch.h b/absl/base/internal/prefetch.h new file mode 100644 index 00000000..a71b3897 --- /dev/null +++ b/absl/base/internal/prefetch.h @@ -0,0 +1,109 @@ +// Copyright 2022 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_BASE_INTERNAL_PREFETCH_H_ +#define ABSL_BASE_INTERNAL_PREFETCH_H_ + +#include "absl/base/config.h" + +// Compatibility wrappers around __builtin_prefetch, to prefetch data +// for read if supported by the toolchain. + +// Move data into the cache before it is read, or "prefetch" it. +// +// The value of `addr` is the address of the memory to prefetch. If +// the target and compiler support it, data prefetch instructions are +// generated. If the prefetch is done some time before the memory is +// read, it may be in the cache by the time the read occurs. +// +// The function names specify the temporal locality heuristic applied, +// using the names of Intel prefetch instructions: +// +// T0 - high degree of temporal locality; data should be left in as +// many levels of the cache possible +// T1 - moderate degree of temporal locality +// T2 - low degree of temporal locality +// Nta - no temporal locality, data need not be left in the cache +// after the read +// +// Incorrect or gratuitous use of these functions can degrade +// performance, so use them only when representative benchmarks show +// an improvement. +// +// Example usage: +// +// absl::base_internal::PrefetchT0(addr); +// +// Currently, the different prefetch calls behave on some Intel +// architectures as follows: +// +// SNB..SKL SKX +// PrefetchT0() L1/L2/L3 L1/L2 +// PrefetchT1() L2/L3 L2 +// PrefetchT2() L2/L3 L2 +// PrefetchNta() L1/--/L3 L1* +// +// * On SKX PrefetchNta() will bring the line into L1 but will evict +// from L3 cache. This might result in surprising behavior. +// +// SNB = Sandy Bridge, SKL = Skylake, SKX = Skylake Xeon. +// +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace base_internal { + +void PrefetchT0(const void* addr); +void PrefetchT1(const void* addr); +void PrefetchT2(const void* addr); +void PrefetchNta(const void* addr); + +// Implementation details follow. + +#if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__) + +// See __builtin_prefetch: +// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html. +// +// These functions speculatively load for read only. This is +// safe for all currently supported platforms. However, prefetch for +// store may have problems depending on the target platform. +// +inline void PrefetchT0(const void* addr) { + // Note: this uses prefetcht0 on Intel. + __builtin_prefetch(addr, 0, 3); +} +inline void PrefetchT1(const void* addr) { + // Note: this uses prefetcht1 on Intel. + __builtin_prefetch(addr, 0, 2); +} +inline void PrefetchT2(const void* addr) { + // Note: this uses prefetcht2 on Intel. + __builtin_prefetch(addr, 0, 1); +} +inline void PrefetchNta(const void* addr) { + // Note: this uses prefetchtnta on Intel. + __builtin_prefetch(addr, 0, 0); +} +#else +inline void PrefetchT0(const void*) {} +inline void PrefetchT1(const void*) {} +inline void PrefetchT2(const void*) {} +inline void PrefetchNta(const void*) {} +#endif + +} // namespace base_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_BASE_INTERNAL_PREFETCH_H_ diff --git a/absl/base/internal/prefetch_test.cc b/absl/base/internal/prefetch_test.cc new file mode 100644 index 00000000..7c1dae46 --- /dev/null +++ b/absl/base/internal/prefetch_test.cc @@ -0,0 +1,43 @@ +// Copyright 2022 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/base/internal/prefetch.h" + +#include "gtest/gtest.h" + +namespace { + +int number = 42; + +TEST(Prefetch, TemporalLocalityNone) { + absl::base_internal::PrefetchNta(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, TemporalLocalityLow) { + absl::base_internal::PrefetchT2(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, TemporalLocalityMedium) { + absl::base_internal::PrefetchT1(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, TemporalLocalityHigh) { + absl::base_internal::PrefetchT0(&number); + EXPECT_EQ(number, 42); +} + +} // namespace diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h index 13779eda..cbb24693 100644 --- a/absl/container/flat_hash_map.h +++ b/absl/container/flat_hash_map.h @@ -76,7 +76,7 @@ struct FlatHashMapPolicy; // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // -// Using `absl::flat_hash_map` at interface boundries in dynamically loaded +// Using `absl::flat_hash_map` at interface boundaries in dynamically loaded // libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may // be randomized across dynamically loaded libraries. // diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h index 304c2abb..4938c703 100644 --- a/absl/container/flat_hash_set.h +++ b/absl/container/flat_hash_set.h @@ -72,7 +72,7 @@ struct FlatHashSetPolicy; // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // -// Using `absl::flat_hash_set` at interface boundries in dynamically loaded +// Using `absl::flat_hash_set` at interface boundaries in dynamically loaded // libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may // be randomized across dynamically loaded libraries. // diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h index f2175d16..c91cae69 100644 --- a/absl/container/node_hash_map.h +++ b/absl/container/node_hash_map.h @@ -78,7 +78,7 @@ class NodeHashMapPolicy; // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // -// Using `absl::node_hash_map` at interface boundries in dynamically loaded +// Using `absl::node_hash_map` at interface boundaries in dynamically loaded // libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may // be randomized across dynamically loaded libraries. // diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h index a9ff7e1b..f2cc70c3 100644 --- a/absl/container/node_hash_set.h +++ b/absl/container/node_hash_set.h @@ -74,7 +74,7 @@ struct NodeHashSetPolicy; // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // -// Using `absl::node_hash_set` at interface boundries in dynamically loaded +// Using `absl::node_hash_set` at interface boundaries in dynamically loaded // libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may // be randomized across dynamically loaded libraries. // diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc index e63ac4a3..40eb055f 100644 --- a/absl/debugging/internal/vdso_support.cc +++ b/absl/debugging/internal/vdso_support.cc @@ -69,7 +69,9 @@ ABSL_CONST_INIT std::atomic VDSOSupport::vdso_base_( debugging_internal::ElfMemImage::kInvalidBase); -std::atomic VDSOSupport::getcpu_fn_(&InitAndGetCPU); +ABSL_CONST_INIT std::atomic VDSOSupport::getcpu_fn_( + &InitAndGetCPU); + VDSOSupport::VDSOSupport() // If vdso_base_ is still set to kInvalidBase, we got here // before VDSOSupport::Init has been called. Call it now. diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h index 5ca5e589..6ae418e7 100644 --- a/absl/strings/internal/cord_internal.h +++ b/absl/strings/internal/cord_internal.h @@ -411,7 +411,8 @@ struct ConstInitExternalStorage { }; template -CordRepExternal ConstInitExternalStorage::value(Str::value); +ABSL_CONST_INIT CordRepExternal + ConstInitExternalStorage::value(Str::value); enum { kMaxInline = 15, diff --git a/absl/strings/internal/escaping.cc b/absl/strings/internal/escaping.cc index 7f87e124..cfea0961 100644 --- a/absl/strings/internal/escaping.cc +++ b/absl/strings/internal/escaping.cc @@ -21,7 +21,7 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { -const char kBase64Chars[] = +ABSL_CONST_INIT const char kBase64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) { diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index cbd84c91..e798fc69 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc @@ -757,8 +757,8 @@ struct LookupTables { // // uint128& operator/=(uint128) is not constexpr, so hardcode the resulting // array to avoid a static initializer. -template<> -const uint128 LookupTables::kVmaxOverBase[] = { +template <> +ABSL_CONST_INIT const uint128 LookupTables::kVmaxOverBase[] = { 0, 0, MakeUint128(9223372036854775807u, 18446744073709551615u), @@ -809,8 +809,8 @@ const uint128 LookupTables::kVmaxOverBase[] = { // // int128& operator/=(int128) is not constexpr, so hardcode the resulting array // to avoid a static initializer. -template<> -const int128 LookupTables::kVmaxOverBase[] = { +template <> +ABSL_CONST_INIT const int128 LookupTables::kVmaxOverBase[] = { 0, 0, MakeInt128(4611686018427387903, 18446744073709551615u), @@ -862,8 +862,8 @@ const int128 LookupTables::kVmaxOverBase[] = { // // int128& operator/=(int128) is not constexpr, so hardcode the resulting array // to avoid a static initializer. -template<> -const int128 LookupTables::kVminOverBase[] = { +template <> +ABSL_CONST_INIT const int128 LookupTables::kVminOverBase[] = { 0, 0, MakeInt128(-4611686018427387904, 0u), @@ -904,11 +904,11 @@ const int128 LookupTables::kVminOverBase[] = { }; template -const IntType LookupTables::kVmaxOverBase[] = +ABSL_CONST_INIT const IntType LookupTables::kVmaxOverBase[] = X_OVER_BASE_INITIALIZER(std::numeric_limits::max()); template -const IntType LookupTables::kVminOverBase[] = +ABSL_CONST_INIT const IntType LookupTables::kVminOverBase[] = X_OVER_BASE_INITIALIZER(std::numeric_limits::min()); #undef X_OVER_BASE_INITIALIZER diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h index 772008c7..7c402ece 100644 --- a/absl/types/internal/variant.h +++ b/absl/types/internal/variant.h @@ -16,8 +16,8 @@ // separate file to avoid cluttering the top of the API header with // implementation details. -#ifndef ABSL_TYPES_variant_internal_H_ -#define ABSL_TYPES_variant_internal_H_ +#ifndef ABSL_TYPES_VARIANT_INTERNAL_H_ +#define ABSL_TYPES_VARIANT_INTERNAL_H_ #include #include @@ -1643,4 +1643,4 @@ ABSL_NAMESPACE_END } // namespace absl #endif // !defined(ABSL_USES_STD_VARIANT) -#endif // ABSL_TYPES_variant_internal_H_ +#endif // ABSL_TYPES_VARIANT_INTERNAL_H_ -- cgit v1.2.3 From 173dfe4a4c70f294a512aae4d0d0f5fc7db39241 Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Wed, 4 May 2022 20:58:05 -0700 Subject: raw_logging: Rename SafeWriteToStderr to indicate what about it is safe (answer: it's async-signal-safe). Also, preserve errno across calls to make it actually signal-safe. PiperOrigin-RevId: 446620926 Change-Id: I875fbec02b909e8424ddf763303b0d6007f8548f --- absl/base/BUILD.bazel | 1 + absl/base/CMakeLists.txt | 1 + absl/base/internal/raw_logging.cc | 8 ++++++-- absl/base/internal/raw_logging.h | 9 +++------ absl/debugging/BUILD.bazel | 1 - absl/debugging/CMakeLists.txt | 1 - absl/debugging/failure_signal_handler.cc | 4 +--- 7 files changed, 12 insertions(+), 13 deletions(-) (limited to 'absl/debugging') diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 49e3a95f..b7e49359 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -75,6 +75,7 @@ cc_library( ":atomic_hook", ":config", ":core_headers", + ":errno_saver", ":log_severity", ], ) diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 0e1e0413..ed55093a 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -66,6 +66,7 @@ absl_cc_library( absl::atomic_hook absl::config absl::core_headers + absl::errno_saver absl::log_severity COPTS ${ABSL_DEFAULT_COPTS} diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index acf20f2a..ca2a75f3 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc @@ -24,6 +24,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/atomic_hook.h" +#include "absl/base/internal/errno_saver.h" #include "absl/base/log_severity.h" // We know how to perform low-level writes to stderr in POSIX and Windows. For @@ -169,7 +170,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line, } else { DoRawLog(&buf, &size, "%s", kTruncated); } - SafeWriteToStderr(buffer, strlen(buffer)); + AsyncSignalSafeWriteToStderr(buffer, strlen(buffer)); } #else static_cast(format); @@ -196,8 +197,11 @@ void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line, } // namespace -void SafeWriteToStderr(const char *s, size_t len) { +void AsyncSignalSafeWriteToStderr(const char* s, size_t len) { + absl::base_internal::ErrnoSaver errno_saver; #if defined(ABSL_HAVE_SYSCALL_WRITE) + // We prefer calling write via `syscall` to minimize the risk of libc doing + // something "helpful". syscall(SYS_write, STDERR_FILENO, s, len); #elif defined(ABSL_HAVE_POSIX_WRITE) write(STDERR_FILENO, s, len); diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h index efe28dac..68a8bf21 100644 --- a/absl/base/internal/raw_logging.h +++ b/absl/base/internal/raw_logging.h @@ -109,12 +109,9 @@ namespace raw_logging_internal { void RawLog(absl::LogSeverity severity, const char* file, int line, const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5); -// Writes the provided buffer directly to stderr, in a safe, low-level manner. -// -// In POSIX this means calling write(), which is async-signal safe and does -// not malloc. If the platform supports the SYS_write syscall, we invoke that -// directly to side-step any libc interception. -void SafeWriteToStderr(const char *s, size_t len); +// Writes the provided buffer directly to stderr, in a signal-safe, low-level +// manner. +void AsyncSignalSafeWriteToStderr(const char* s, size_t len); // compile-time function to get the "base" filename, that is, the part of // a filename after the last "/" or "\" path separator. The search starts at diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index 7f5c1cad..dce59e1d 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -143,7 +143,6 @@ cc_library( "//absl/base", "//absl/base:config", "//absl/base:core_headers", - "//absl/base:errno_saver", "//absl/base:raw_logging_internal", ], ) diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index 7507ff3b..32952734 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -126,7 +126,6 @@ absl_cc_library( absl::base absl::config absl::core_headers - absl::errno_saver absl::raw_logging_internal PUBLIC ) diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index 3fe8827a..affade3b 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -42,7 +42,6 @@ #include #include "absl/base/attributes.h" -#include "absl/base/internal/errno_saver.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/sysinfo.h" #include "absl/debugging/internal/examine_stack.h" @@ -217,8 +216,7 @@ static void InstallOneFailureHandler(FailureSignalData* data, #endif static void WriteToStderr(const char* data) { - absl::base_internal::ErrnoSaver errno_saver; - absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data)); + absl::raw_logging_internal::AsyncSignalSafeWriteToStderr(data, strlen(data)); } static void WriteSignalMessage(int signo, int cpu, -- cgit v1.2.3 From 4bb6a0e045c211576c7066e7862ae212e8333639 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Wed, 25 May 2022 13:50:51 -0700 Subject: Fix detection of ABSL_HAVE_ELF_MEM_IMAGE on Haiku Fixes #1181 ORIGINAL_AUTHOR=jerome.duval@gmail.com PiperOrigin-RevId: 451006334 Change-Id: Id61e5889fb55594d09e92e7bb98fdf8bfbc13cc4 --- absl/debugging/internal/elf_mem_image.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index e4bbf2d7..113071a9 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -31,8 +31,9 @@ #error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set #endif -#if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \ - !defined(__native_client__) && !defined(__asmjs__) && !defined(__wasm__) +#if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \ + !defined(__native_client__) && !defined(__asmjs__) && \ + !defined(__wasm__) && !defined(__HAIKU__) #define ABSL_HAVE_ELF_MEM_IMAGE 1 #endif -- cgit v1.2.3 From c588201b688ffce93758ff4ca17aecc24b5ab460 Mon Sep 17 00:00:00 2001 From: Jeremy Nimmer Date: Mon, 6 Jun 2022 13:13:36 -0700 Subject: Obey ABSL_DEFAULT_LINKOPTS for all cc_library targets A few targets were missing `linkopts = ...` and so were not obeying the project-wide default settings. Omit any changes to cctz for now, because it's vendored from another project. --- absl/debugging/BUILD.bazel | 1 + absl/random/BUILD.bazel | 1 + absl/random/internal/BUILD.bazel | 2 ++ absl/status/BUILD.bazel | 3 +++ absl/strings/BUILD.bazel | 18 ++++++++++++++++++ absl/types/BUILD.bazel | 1 + 6 files changed, 26 insertions(+) (limited to 'absl/debugging') diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index dce59e1d..932a8e9f 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -196,6 +196,7 @@ cc_library( srcs = ["internal/demangle.cc"], hdrs = ["internal/demangle.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ "//absl/base", diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel index 27f3e334..d983685c 100644 --- a/absl/random/BUILD.bazel +++ b/absl/random/BUILD.bazel @@ -128,6 +128,7 @@ cc_library( name = "mock_distributions", testonly = 1, hdrs = ["mock_distributions.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":distributions", ":mocking_bit_gen", diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel index 69f9f80c..fd5b6195 100644 --- a/absl/random/internal/BUILD.bazel +++ b/absl/random/internal/BUILD.bazel @@ -502,6 +502,7 @@ cc_test( cc_library( name = "mock_helpers", hdrs = ["mock_helpers.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:fast_type_id", "//absl/types:optional", @@ -512,6 +513,7 @@ cc_library( name = "mock_overload_set", testonly = 1, hdrs = ["mock_overload_set.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":mock_helpers", "//absl/random:mocking_bit_gen", diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel index b334f31d..ce0ea70c 100644 --- a/absl/status/BUILD.bazel +++ b/absl/status/BUILD.bazel @@ -20,6 +20,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -39,6 +40,7 @@ cc_library( "status_payload_printer.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:atomic_hook", "//absl/base:core_headers", @@ -76,6 +78,7 @@ cc_library( "statusor.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":status", "//absl/base", diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 81f5a589..3f51252f 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -16,6 +16,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -65,6 +66,7 @@ cc_library( "substitute.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":internal", "//absl/base", @@ -95,6 +97,7 @@ cc_library( "internal/utf8.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:config", "//absl/base:core_headers", @@ -288,6 +291,7 @@ cc_library( "internal/cord_rep_ring_reader.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//visibility:private", ], @@ -391,6 +395,7 @@ cc_library( name = "cordz_update_tracker", hdrs = ["internal/cordz_update_tracker.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -422,6 +427,7 @@ cc_library( "cord_buffer.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":cord_internal", ":cordz_functions", @@ -452,6 +458,7 @@ cc_library( srcs = ["internal/cordz_handle.cc"], hdrs = ["internal/cordz_handle.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -468,6 +475,7 @@ cc_library( srcs = ["internal/cordz_info.cc"], hdrs = ["internal/cordz_info.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -492,6 +500,7 @@ cc_library( name = "cordz_update_scope", hdrs = ["internal/cordz_update_scope.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -524,6 +533,7 @@ cc_library( srcs = ["internal/cordz_sample_token.cc"], hdrs = ["internal/cordz_sample_token.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -539,6 +549,7 @@ cc_library( srcs = ["internal/cordz_functions.cc"], hdrs = ["internal/cordz_functions.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -554,6 +565,7 @@ cc_library( name = "cordz_statistics", hdrs = ["internal/cordz_statistics.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -663,6 +675,7 @@ cc_library( "cord_test_helpers.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":cord", ":cord_internal", @@ -676,6 +689,7 @@ cc_library( testonly = 1, hdrs = ["internal/cord_rep_test_util.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":cord_internal", ":strings", @@ -689,6 +703,7 @@ cc_library( testonly = 1, hdrs = ["cordz_test_helpers.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":cord", ":cord_internal", @@ -1097,6 +1112,7 @@ cc_library( "str_format.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":str_format_internal", ], @@ -1122,6 +1138,7 @@ cc_library( "internal/str_format/parser.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":strings", @@ -1246,6 +1263,7 @@ cc_library( testonly = True, srcs = ["internal/pow10_helper.cc"], hdrs = ["internal/pow10_helper.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = ["//absl/base:config"], ) diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index 38ed2286..bb801012 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel @@ -314,6 +314,7 @@ cc_library( name = "compare", hdrs = ["compare.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:core_headers", "//absl/meta:type_traits", -- cgit v1.2.3 From 7a8d20b7841b43cc685230058130bd0f019e4004 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 8 Jun 2022 12:42:23 -0700 Subject: absl: correct the stack trace path on RISCV When we would perform a stacktrace using the frame pointer walking, because we did the adjustment for the return address separately, we were misaligning the stack size and frame. Simplify the logic and correct the offset. The recovered frame pointer provides us with the return address of the current frame and the previous frame's frame pointer. Subsequently, we decide if we want to record this frame or not. The value in `next_frame_pointer` already points to the value from the previous stack frame (that is the next frame pointer to iterate). As such, the value computed by `ComputeStackFrameSize` is the value for the current frame. This was offset by one previously. Take the opportunity to clean up some of the local comments, fixing typos and splitting up the comments to reflect the lines that they are associated with. PiperOrigin-RevId: 453744059 Change-Id: If14813e0ac36f327f4b7594472f2222d05c478aa --- absl/debugging/internal/stacktrace_riscv-inl.inc | 25 +++++++++++------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'absl/debugging') diff --git a/absl/debugging/internal/stacktrace_riscv-inl.inc b/absl/debugging/internal/stacktrace_riscv-inl.inc index 98b09a22..7123b71b 100644 --- a/absl/debugging/internal/stacktrace_riscv-inl.inc +++ b/absl/debugging/internal/stacktrace_riscv-inl.inc @@ -171,26 +171,21 @@ ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, const void *ucp, int *min_dropped_frames) { + // The `frame_pointer` that is computed here points to the top of the frame. + // The two words preceding the address are the return address and the previous + // frame pointer. #if defined(__GNUC__) void **frame_pointer = reinterpret_cast(__builtin_frame_address(0)); #else #error reading stack pointer not yet supported on this platform #endif - skip_count++; // Skip the frame for this function. int n = 0; - - // The `frame_pointer` that is computed here points to the top of the frame. - // The two words preceding the address are the return address and the previous - // frame pointer. To find a PC value associated with the current frame, we - // need to go down a level in the call chain. So we remember the return - // address of the last frame seen. This does not work for the first stack - // frame, which belongs to `UnwindImp()` but we skip the frame for - // `UnwindImp()` anyway. - void *prev_return_address = nullptr; - + void *return_address = nullptr; while (frame_pointer && n < max_depth) { - // The absl::GetStackFrames routine si called when we are in some + return_address = frame_pointer[-1]; + + // The absl::GetStackFrames routine is called when we are in some // informational context (the failure signal handler for example). Use the // non-strict unwinding rules to produce a stack trace that is as complete // as possible (even if it contains a few bogus entries in some rare cases). @@ -200,15 +195,16 @@ static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, if (skip_count > 0) { skip_count--; } else { - result[n] = prev_return_address; + result[n] = return_address; if (IS_STACK_FRAMES) { sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer); } n++; } - prev_return_address = frame_pointer[-1]; + frame_pointer = next_frame_pointer; } + if (min_dropped_frames != nullptr) { // Implementation detail: we clamp the max of frames we are willing to // count, so as not to spend too much time in the loop below. @@ -225,6 +221,7 @@ static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, } *min_dropped_frames = num_dropped_frames; } + return n; } -- cgit v1.2.3 From 01cc6567cff77738e416a7ddc17de2d435a780ce Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Tue, 21 Jun 2022 12:27:47 -0700 Subject: PR #1200: absl/debugging/CMakeLists.txt: link with libexecinfo if needed Imported from GitHub PR https://github.com/abseil/abseil-cpp/pull/1200 `backtrace` and `execinfo.h` can be provided by libexecinfo on uclibc and musl resulting in the following build failure with any user of abseil-cpp (such as collectd): ``` /home/buildroot/autobuild/instance-0/output-1/host/lib/gcc/sparc-buildroot-linux-uclibc/10.3.0/../../../../sparc-buildroot-linux-uclibc/bin/ld: /home/buildroot/autobuild/instance-0/output-1/host/bin/../sparc-buildroot-linux-uclibc/sysroot/usr/lib/libabsl_stacktrace.so: undefined reference to `backtrace' ``` [...] ``` libgrpc++ . . . . . . no (libgrpc++ not found) ``` [...] ``` configure: error: "Some plugins are missing dependencies - see the summary above for details" ``` Fixes: - http://autobuild.buildroot.org/results/6a0484412f020e763ce3ad5bda48f09c78645bff Signed-off-by: Fabrice Fontaine Merge dac52cd20efb672278dc64bcd74920172a599ac0 into 93ad4284ac12077b7bac07a4743df1c564e7c957 Merging this change closes #1200 COPYBARA_INTEGRATE_REVIEW=https://github.com/abseil/abseil-cpp/pull/1200 from ffontaine:master dac52cd20efb672278dc64bcd74920172a599ac0 PiperOrigin-RevId: 456323163 Change-Id: I3d2206761524d36e2b227c571e2e513f6840ff75 --- absl/debugging/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'absl/debugging') diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index 32952734..d8207d6a 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -14,6 +14,8 @@ # limitations under the License. # +find_library(EXECINFO_LIBRARY execinfo) + absl_cc_library( NAME stacktrace @@ -33,6 +35,8 @@ absl_cc_library( "stacktrace.cc" COPTS ${ABSL_DEFAULT_COPTS} + LINKOPTS + $<$:${EXECINFO_LIBRARY}> DEPS absl::debugging_internal absl::config -- cgit v1.2.3 From 4dc63bade3ef2c099f328f2e08f6d4bf6658f0cf Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 22 Jun 2022 13:55:21 -0700 Subject: Merge contiguous mappings from the same file. This allows symbolization to work if different parts of a binary's text are mapped differently, e.g. if they're mlock()ed or mapped onto huge pages. PiperOrigin-RevId: 456600880 Change-Id: I069264f94cf834df9201968275a00828f5eb077e --- absl/debugging/symbolize_elf.inc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'absl/debugging') diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index ddccd590..9bfdd915 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc @@ -1146,6 +1146,14 @@ bool Symbolizer::RegisterObjFile(const char *filename, reinterpret_cast(old->end_addr), old->filename); } return true; + } else if (old->end_addr == start_addr && + reinterpret_cast(old->start_addr) - old->offset == + reinterpret_cast(start_addr) - offset && + strcmp(old->filename, filename) == 0) { + // Two contiguous map entries that span a contiguous region of the file, + // perhaps because some part of the file was mlock()ed. Combine them. + old->end_addr = end_addr; + return true; } } ObjFile *obj = impl->addr_map_.Add(); -- cgit v1.2.3