|
10 | 10 | #include <cstdlib> |
11 | 11 | #include <cstring> |
12 | 12 | #include <iomanip> |
| 13 | +#include <set> |
13 | 14 | #include <sstream> |
14 | 15 |
|
15 | 16 | #include "src/base/functional.h" |
@@ -103,7 +104,12 @@ struct Flag { |
103 | 104 | const char* cmt_; // A comment about the flags purpose. |
104 | 105 | bool owns_ptr_; // Does the flag own its string value? |
105 | 106 | SetBy set_by_ = SetBy::kDefault; |
| 107 | + // Name of the flag implying this flag, if any. |
106 | 108 | const char* implied_by_ = nullptr; |
| 109 | +#ifdef DEBUG |
| 110 | + // Pointer to the flag implying this flag, if any. |
| 111 | + const Flag* implied_by_ptr_ = nullptr; |
| 112 | +#endif |
107 | 113 |
|
108 | 114 | FlagType type() const { return type_; } |
109 | 115 |
|
@@ -113,6 +119,17 @@ struct Flag { |
113 | 119 |
|
114 | 120 | bool PointsTo(const void* ptr) const { return valptr_ == ptr; } |
115 | 121 |
|
| 122 | +#ifdef DEBUG |
| 123 | + bool ImpliedBy(const void* ptr) const { |
| 124 | + const Flag* current = this->implied_by_ptr_; |
| 125 | + while (current != nullptr) { |
| 126 | + if (current->PointsTo(ptr)) return true; |
| 127 | + current = current->implied_by_ptr_; |
| 128 | + } |
| 129 | + return false; |
| 130 | + } |
| 131 | +#endif |
| 132 | + |
116 | 133 | bool bool_variable() const { return GetValue<TYPE_BOOL, bool>(); } |
117 | 134 |
|
118 | 135 | void set_bool_variable(bool value, SetBy set_by) { |
@@ -333,6 +350,15 @@ struct Flag { |
333 | 350 | if (IsAnyImplication(new_set_by)) { |
334 | 351 | DCHECK_NOT_NULL(implied_by); |
335 | 352 | implied_by_ = implied_by; |
| 353 | +#ifdef DEBUG |
| 354 | + // This only works when implied_by is a flag_name or !flag_name, but it |
| 355 | + // can also be a condition e.g. flag_name > 3. Since this is only used for |
| 356 | + // checks in DEBUG mode, we will just ignore the more complex conditions |
| 357 | + // for now - that will just lead to a nullptr which won't be followed. |
| 358 | + implied_by_ptr_ = static_cast<Flag*>( |
| 359 | + FindFlagByName(implied_by[0] == '!' ? implied_by + 1 : implied_by)); |
| 360 | + DCHECK_NE(implied_by_ptr_, this); |
| 361 | +#endif |
336 | 362 | } |
337 | 363 | return change_flag; |
338 | 364 | } |
@@ -534,17 +560,70 @@ uint32_t ComputeFlagListHash() { |
534 | 560 | std::ostringstream modified_args_as_string; |
535 | 561 | if (COMPRESS_POINTERS_BOOL) modified_args_as_string << "ptr-compr"; |
536 | 562 | if (DEBUG_BOOL) modified_args_as_string << "debug"; |
| 563 | + |
| 564 | +#ifdef DEBUG |
| 565 | + // These two sets are used to check that we don't leave out any flags |
| 566 | + // implied by --predictable in the list below. |
| 567 | + std::set<const char*> flags_implied_by_predictable; |
| 568 | + std::set<const char*> flags_ignored_because_of_predictable; |
| 569 | +#endif |
| 570 | + |
537 | 571 | for (const Flag& flag : flags) { |
538 | 572 | if (flag.IsDefault()) continue; |
| 573 | +#ifdef DEBUG |
| 574 | + if (flag.ImpliedBy(&v8_flags.predictable)) { |
| 575 | + flags_implied_by_predictable.insert(flag.name()); |
| 576 | + } |
| 577 | +#endif |
539 | 578 | // We want to be able to flip --profile-deserialization without |
540 | 579 | // causing the code cache to get invalidated by this hash. |
541 | 580 | if (flag.PointsTo(&v8_flags.profile_deserialization)) continue; |
542 | 581 | // Skip v8_flags.random_seed and v8_flags.predictable to allow predictable |
543 | 582 | // code caching. |
544 | 583 | if (flag.PointsTo(&v8_flags.random_seed)) continue; |
545 | 584 | if (flag.PointsTo(&v8_flags.predictable)) continue; |
| 585 | + |
| 586 | + // The following flags are implied by --predictable (some negated). |
| 587 | + if (flag.PointsTo(&v8_flags.concurrent_sparkplug) || |
| 588 | + flag.PointsTo(&v8_flags.concurrent_recompilation) || |
| 589 | +#ifdef V8_ENABLE_MAGLEV |
| 590 | + flag.PointsTo(&v8_flags.maglev_deopt_data_on_background) || |
| 591 | + flag.PointsTo(&v8_flags.maglev_build_code_on_background) || |
| 592 | +#endif |
| 593 | + flag.PointsTo(&v8_flags.parallel_scavenge) || |
| 594 | + flag.PointsTo(&v8_flags.concurrent_marking) || |
| 595 | + flag.PointsTo(&v8_flags.concurrent_array_buffer_sweeping) || |
| 596 | + flag.PointsTo(&v8_flags.parallel_marking) || |
| 597 | + flag.PointsTo(&v8_flags.concurrent_sweeping) || |
| 598 | + flag.PointsTo(&v8_flags.parallel_compaction) || |
| 599 | + flag.PointsTo(&v8_flags.parallel_pointer_update) || |
| 600 | + flag.PointsTo(&v8_flags.memory_reducer) || |
| 601 | + flag.PointsTo(&v8_flags.cppheap_concurrent_marking) || |
| 602 | + flag.PointsTo(&v8_flags.cppheap_incremental_marking) || |
| 603 | + flag.PointsTo(&v8_flags.single_threaded_gc)) { |
| 604 | +#ifdef DEBUG |
| 605 | + if (flag.ImpliedBy(&v8_flags.predictable)) { |
| 606 | + flags_ignored_because_of_predictable.insert(flag.name()); |
| 607 | + } |
| 608 | +#endif |
| 609 | + continue; |
| 610 | + } |
546 | 611 | modified_args_as_string << flag; |
547 | 612 | } |
| 613 | + |
| 614 | +#ifdef DEBUG |
| 615 | + for (const char* name : flags_implied_by_predictable) { |
| 616 | + if (flags_ignored_because_of_predictable.find(name) == |
| 617 | + flags_ignored_because_of_predictable.end()) { |
| 618 | + PrintF( |
| 619 | + "%s should be added to the list of " |
| 620 | + "flags_ignored_because_of_predictable\n", |
| 621 | + name); |
| 622 | + UNREACHABLE(); |
| 623 | + } |
| 624 | + } |
| 625 | +#endif |
| 626 | + |
548 | 627 | std::string args(modified_args_as_string.str()); |
549 | 628 | // Generate a hash that is not 0. |
550 | 629 | uint32_t hash = static_cast<uint32_t>(base::hash_range( |
|