v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
flags.cc
Go to the documentation of this file.
1// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/flags/flags.h"
6
7#include <algorithm>
8#include <array>
9#include <cctype>
10#include <cerrno>
11#include <cinttypes>
12#include <cstdlib>
13#include <cstring>
14#include <iomanip>
15#include <optional>
16#include <set>
17#include <sstream>
18
19#include "src/base/hashing.h"
27#include "src/utils/memcopy.h"
28#include "src/utils/ostreams.h"
29#include "src/utils/utils.h"
30
31#if V8_ENABLE_WEBASSEMBLY
33#endif // V8_ENABLE_WEBASSEMBLY
34
35namespace v8::internal {
36
37// Define {v8_flags}, declared in flags.h.
39
40// {v8_flags} needs to be aligned to a memory page, and the size needs to be a
41// multiple of a page size. This is required for memory-protection of the memory
42// holding the {v8_flags} struct.
43// Both is guaranteed by the {alignas(kMinimumOSPageSize)} annotation on
44// {FlagValues}.
45static_assert(alignof(FlagValues) == kMinimumOSPageSize);
46static_assert(sizeof(FlagValues) % kMinimumOSPageSize == 0);
47
48// Define all of our flags default values.
49#define FLAG_MODE_DEFINE_DEFAULTS
50#include "src/flags/flag-definitions.h" // NOLINT(build/include)
51#undef FLAG_MODE_DEFINE_DEFAULTS
52
53char FlagHelpers::NormalizeChar(char ch) { return ch == '_' ? '-' : ch; }
54
55int FlagHelpers::FlagNamesCmp(const char* a, const char* b) {
56 int i = 0;
57 char ac, bc;
58 do {
59 ac = NormalizeChar(a[i]);
60 bc = NormalizeChar(b[i]);
61 if (ac < bc) return -1;
62 if (ac > bc) return 1;
63 i++;
64 } while (ac != '\0');
65 DCHECK_EQ(bc, '\0');
66 return 0;
67}
68
69bool FlagHelpers::EqualNames(const char* a, const char* b) {
70 return FlagNamesCmp(a, b) == 0;
71}
72
73// Checks if two flag names are equal, allowing for the second name to have a
74// suffix starting with a white space character, e.g. "max_opt < 3". This is
75// used in flag implications.
76bool FlagHelpers::EqualNameWithSuffix(const char* a, const char* b) {
77 char ac, bc;
78 for (int i = 0; true; ++i) {
79 ac = NormalizeChar(a[i]);
80 bc = NormalizeChar(b[i]);
81 if (ac == '\0') break;
82 if (ac != bc) return false;
83 }
84 return bc == '\0' || std::isspace(bc);
85}
86
87std::ostream& operator<<(std::ostream& os, FlagName flag_name) {
88 os << (flag_name.negated ? "--no-" : "--");
89 for (const char* p = flag_name.name; *p; ++p) {
91 }
92 return os;
93}
94
95void Flag::set_string_value(const char* new_value, bool owns_new_value,
96 SetBy set_by) {
98 DCHECK_IMPLIES(owns_new_value, new_value != nullptr);
99 const char* old_value = string_value();
100 DCHECK_IMPLIES(owns_ptr_, old_value != nullptr);
101 bool change_flag = old_value
102 ? !new_value || std::strcmp(old_value, new_value) != 0
103 : !!new_value;
105 if (change_flag) {
106 DCHECK(!IsReadOnly());
107 if (owns_ptr_) DeleteArray(old_value);
108 *reinterpret_cast<FlagValue<const char*>*>(valptr_) = new_value;
109 owns_ptr_ = owns_new_value;
110 } else {
111 if (owns_new_value) DeleteArray(new_value);
112 }
113}
114
116 if (v8_flags.allow_overwriting_for_next_flag) {
117 // Setting the flag manually to false before calling Reset() avoids this
118 // becoming re-entrant.
119 v8_flags.allow_overwriting_for_next_flag = false;
120 FindFlagByPointer(&v8_flags.allow_overwriting_for_next_flag)->Reset();
121 return false;
122 }
123 return v8_flags.abort_on_contradictory_flags && !v8_flags.fuzzing;
124}
125
126bool Flag::CheckFlagChange(SetBy new_set_by, bool change_flag,
127 const char* implied_by) {
128 if (new_set_by == SetBy::kWeakImplication &&
130 return false;
131 }
133 static constexpr const char kHint[] =
134 "If a test variant caused this, it might be necessary to specify "
135 "additional contradictory flags in "
136 "tools/testrunner/local/variants.py.";
137 struct FatalError : public std::ostringstream {
138 // MSVC complains about non-returning destructor; disable that.
140 ~FatalError() { FATAL("%s.\n%s", str().c_str(), kHint); }
141 };
142 // Readonly flags cannot change value.
143 if (change_flag && IsReadOnly()) {
144 // Exit instead of abort for certain testing situations.
145 if (v8_flags.exit_on_contradictory_flags) base::OS::ExitProcess(0);
146 if (implied_by == nullptr) {
147 FatalError{} << "Contradictory value for readonly flag "
148 << FlagName{name()};
149 } else {
150 DCHECK(IsAnyImplication(new_set_by));
151 FatalError{} << "Contradictory value for readonly flag "
152 << FlagName{name()} << " implied by " << implied_by;
153 }
154 }
155 // For bool flags, we only check for a conflict if the value actually
156 // changes. So specifying the same flag with the same value multiple times
157 // is allowed.
158 // For other flags, we disallow specifying them explicitly or in the
159 // presence of an implication if the value is not the same.
160 // This is to simplify the rules describing conflicts in variants.py: A
161 // repeated non-boolean flag is considered an error.
164 switch (set_by_) {
165 case SetBy::kDefault:
166 break;
168 if (new_set_by == SetBy::kWeakImplication && check_implications) {
169 FatalError{} << "Contradictory weak flag implications from "
170 << FlagName{implied_by_} << " and "
171 << FlagName{implied_by} << " for flag "
172 << FlagName{name()};
173 }
174 break;
176 if (new_set_by == SetBy::kImplication && check_implications) {
177 FatalError{} << "Contradictory flag implications from "
178 << FlagName{implied_by_} << " and "
179 << FlagName{implied_by} << " for flag "
180 << FlagName{name()};
181 }
182 break;
184 if (new_set_by == SetBy::kImplication && check_implications) {
185 // Exit instead of abort for certain testing situations.
186 if (v8_flags.exit_on_contradictory_flags) base::OS::ExitProcess(0);
187 if (is_bool_flag) {
188 FatalError{} << "Flag " << FlagName{name()} << ": value implied by "
189 << FlagName{implied_by}
190 << " conflicts with explicit specification";
191 } else {
192 FatalError{} << "Flag " << FlagName{name()} << " is implied by "
193 << FlagName{implied_by}
194 << " but also specified explicitly";
195 }
196 } else if (new_set_by == SetBy::kCommandLine && check_implications) {
197 // Exit instead of abort for certain testing situations.
198 if (v8_flags.exit_on_contradictory_flags) base::OS::ExitProcess(0);
199 if (is_bool_flag) {
200 FatalError{} << "Command-line provided flag " << FlagName{name()}
201 << " specified as both true and false";
202 } else {
203 FatalError{} << "Command-line provided flag " << FlagName{name()}
204 << " specified multiple times";
205 }
206 }
207 break;
208 }
209 }
210 if (change_flag && IsReadOnly()) {
211 // Readonly flags must never change value.
212 return false;
213 }
214 set_by_ = new_set_by;
215 if (IsAnyImplication(new_set_by)) {
216 DCHECK_NOT_NULL(implied_by);
217 implied_by_ = implied_by;
218#ifdef DEBUG
219 // This only works when implied_by is a flag_name or !flag_name, but it
220 // can also be a condition e.g. flag_name > 3. Since this is only used for
221 // checks in DEBUG mode, we will just ignore the more complex conditions
222 // for now - that will just lead to a nullptr which won't be followed.
223 implied_by_ptr_ = static_cast<Flag*>(FindImplicationFlagByName(
224 implied_by[0] == '!' ? implied_by + 1 : implied_by));
225 DCHECK_NE(implied_by_ptr_, this);
226#endif
227 }
228 return change_flag;
230
231bool Flag::IsDefault() const {
232 switch (type_) {
233 case TYPE_BOOL:
234 return bool_variable() == bool_default();
235 case TYPE_MAYBE_BOOL:
236 return maybe_bool_variable().has_value() == false;
237 case TYPE_INT:
238 return int_variable() == int_default();
240 return uint_variable() == uint_default();
241 case TYPE_UINT64:
242 return uint64_variable() == uint64_default();
243 case TYPE_FLOAT:
244 return float_variable() == float_default();
246 return size_t_variable() == size_t_default();
247 case TYPE_STRING: {
248 const char* str1 = string_value();
249 const char* str2 = string_default();
250 if (str2 == nullptr) return str1 == nullptr;
251 if (str1 == nullptr) return str2 == nullptr;
252 return strcmp(str1, str2) == 0;
254 }
255 UNREACHABLE();
256}
257
259 if (type_ != TYPE_STRING) return;
261}
262
263void Flag::Reset() {
264 switch (type_) {
265 case TYPE_BOOL:
267 break;
268 case TYPE_MAYBE_BOOL:
270 break;
271 case TYPE_INT:
273 break;
274 case TYPE_UINT:
276 break;
277 case TYPE_UINT64:
279 break;
280 case TYPE_FLOAT:
282 break;
283 case TYPE_SIZE_T:
285 break;
286 case TYPE_STRING:
288 break;
289 }
290}
291
292Flag flags[] = {
293#define FLAG_MODE_META
294#include "src/flags/flag-definitions.h" // NOLINT(build/include)
295#undef FLAG_MODE_META
296};
297
298constexpr size_t kNumFlags = arraysize(flags);
299
301
302struct FlagLess {
303 bool operator()(const Flag* a, const Flag* b) const {
304 return FlagHelpers::FlagNamesCmp(a->name(), b->name()) < 0;
305 }
306};
307
309 bool operator()(const Flag* a, const char* b) const {
310 return FlagHelpers::FlagNamesCmp(a->name(), b) > 0;
311 }
312};
313
314// Optimized look-up of flags by name using binary search. Works only for flags
315// that can be found. If the looked-up flag might not exit in the list, an
316// additional name check of the returned flag is required.
318 public:
320 for (size_t i = 0; i < kNumFlags; ++i) {
321 flags_[i] = &flags[i];
322 }
323 std::sort(flags_.begin(), flags_.end(), FlagLess());
324 }
325
326 // Returns the greatest flag whose name is less than or equal to the given
327 // name (lexicographically). This allows for finding the right flag even if
328 // there is a suffix, as in the case of implications, e.g. "max_opt < 3".
329 Flag* GetFlag(const char* name) {
330 auto it = std::lower_bound(flags_.rbegin(), flags_.rend(), name,
332 if (it == flags_.rend()) return nullptr;
333 return *it;
334 }
335
336 private:
337 std::array<Flag*, kNumFlags> flags_;
338};
339
341
342// This should be used to look up flags that we know were defined.
343// It allows for suffixes used in implications, e.g. "max_opt < 3",
344Flag* FindImplicationFlagByName(const char* name) {
345 Flag* flag = GetFlagMap()->GetFlag(name);
346 CHECK(flag != nullptr);
347 DCHECK(FlagHelpers::EqualNameWithSuffix(flag->name(), name));
348 return flag;
349}
350
351// This can be used to look up flags that might not exist (e.g. invalid command
352// line flags).
353Flag* FindFlagByName(const char* name) {
354 Flag* flag = GetFlagMap()->GetFlag(name);
355 // GetFlag returns an invalid lower bound for flags not in the list. So
356 // we need to verify the name again.
357 if (flag != nullptr && FlagHelpers::EqualNames(flag->name(), name)) {
358 return flag;
359 }
360#ifdef DEBUG
361 // Ensure the flag is not in the global list.
362 for (size_t i = 0; i < kNumFlags; ++i) {
363 DCHECK(!FlagHelpers::EqualNames(name, flags[i].name()));
364 }
365#endif
366 return nullptr;
367}
369Flag* FindFlagByPointer(const void* ptr) {
370 for (size_t i = 0; i < kNumFlags; ++i) {
371 if (flags[i].PointsTo(ptr)) return &flags[i];
372 }
373 return nullptr;
374}
376static const char* Type2String(Flag::FlagType type) {
377 switch (type) {
378 case Flag::TYPE_BOOL:
379 return "bool";
381 return "maybe_bool";
382 case Flag::TYPE_INT:
383 return "int";
384 case Flag::TYPE_UINT:
385 return "uint";
387 return "uint64";
388 case Flag::TYPE_FLOAT:
389 return "float";
391 return "size_t";
393 return "string";
394 }
395}
396
397// Helper for printing flag values.
399 const Flag& flag;
400};
401
402std::ostream& operator<<(std::ostream& os, PrintFlagValue flag_value) {
403 const Flag& flag = flag_value.flag;
404 switch (flag.type()) {
405 case Flag::TYPE_BOOL:
406 os << (flag.bool_variable() ? "true" : "false");
407 break;
409 os << (flag.maybe_bool_variable().has_value()
410 ? (flag.maybe_bool_variable().value() ? "true" : "false")
411 : "unset");
412 break;
413 case Flag::TYPE_INT:
414 os << flag.int_variable();
415 break;
416 case Flag::TYPE_UINT:
417 os << flag.uint_variable();
418 break;
420 os << flag.uint64_variable();
421 break;
422 case Flag::TYPE_FLOAT:
423 os << flag.float_variable();
424 break;
426 os << flag.size_t_variable();
427 break;
428 case Flag::TYPE_STRING: {
429 const char* str = flag.string_value();
430 os << std::quoted(str ? str : "");
431 break;
432 }
433 }
434 return os;
435}
436
437std::ostream& operator<<(std::ostream& os, const Flag& flag) {
438 if (flag.type() == Flag::TYPE_BOOL) {
439 os << FlagName{flag.name(), !flag.bool_variable()};
440 } else {
441 os << FlagName{flag.name()} << "=" << PrintFlagValue{flag};
442 }
443 return os;
444}
445
446static std::atomic<uint32_t> flag_hash{0};
447static std::atomic<bool> flags_frozen{false};
448
450 std::ostringstream modified_args_as_string;
451 if (COMPRESS_POINTERS_BOOL) modified_args_as_string << "ptr-compr";
452 if (DEBUG_BOOL) modified_args_as_string << "debug";
453
454#ifdef DEBUG
455 // These two sets are used to check that we don't leave out any flags
456 // implied by --predictable in the list below.
457 std::set<const char*> flags_implied_by_predictable;
458 std::set<const char*> flags_ignored_because_of_predictable;
459#endif
461 for (const Flag& flag : flags) {
462 if (flag.IsDefault()) continue;
463#ifdef DEBUG
464 if (flag.ImpliedBy(&v8_flags.predictable)) {
465 flags_implied_by_predictable.insert(flag.name());
466 }
467#endif
468 // We want to be able to flip --profile-deserialization without
469 // causing the code cache to get invalidated by this hash.
470 if (flag.PointsTo(&v8_flags.profile_deserialization)) continue;
471 // Skip v8_flags.random_seed and v8_flags.predictable to allow predictable
472 // code caching.
473 if (flag.PointsTo(&v8_flags.random_seed)) continue;
474 if (flag.PointsTo(&v8_flags.predictable)) continue;
475
476 // The following flags are implied by --predictable (some negated).
477 if (flag.PointsTo(&v8_flags.concurrent_sparkplug) ||
478 flag.PointsTo(&v8_flags.concurrent_recompilation) ||
479 flag.PointsTo(&v8_flags.lazy_feedback_allocation) ||
480#ifdef V8_ENABLE_MAGLEV
481 flag.PointsTo(&v8_flags.maglev_deopt_data_on_background) ||
482 flag.PointsTo(&v8_flags.maglev_build_code_on_background) ||
483#endif
484 flag.PointsTo(&v8_flags.parallel_scavenge) ||
485 flag.PointsTo(&v8_flags.concurrent_marking) ||
486 flag.PointsTo(&v8_flags.concurrent_minor_ms_marking) ||
487 flag.PointsTo(&v8_flags.concurrent_array_buffer_sweeping) ||
488 flag.PointsTo(&v8_flags.parallel_marking) ||
489 flag.PointsTo(&v8_flags.concurrent_sweeping) ||
490 flag.PointsTo(&v8_flags.parallel_compaction) ||
491 flag.PointsTo(&v8_flags.parallel_pointer_update) ||
492 flag.PointsTo(&v8_flags.parallel_weak_ref_clearing) ||
493 flag.PointsTo(&v8_flags.memory_reducer) ||
494 flag.PointsTo(&v8_flags.cppheap_concurrent_marking) ||
495 flag.PointsTo(&v8_flags.cppheap_incremental_marking) ||
496 flag.PointsTo(&v8_flags.single_threaded_gc) ||
497 flag.PointsTo(&v8_flags.fuzzing_and_concurrent_recompilation) ||
498 flag.PointsTo(&v8_flags.predictable_and_random_seed_is_0)) {
499#ifdef DEBUG
500 if (flag.ImpliedBy(&v8_flags.predictable)) {
501 flags_ignored_because_of_predictable.insert(flag.name());
503#endif
504 continue;
506 modified_args_as_string << flag;
507 }
508
509#ifdef DEBUG
510 // Disable the check for fuzzing. This check is only here
511 // to ensure that we can generate reproducible code cache
512 // for production builds, we don't care as much about the
513 // reproducibility in the case of fuzzing.
514 if (!v8_flags.fuzzing) {
515 for (const char* name : flags_implied_by_predictable) {
516 if (flags_ignored_because_of_predictable.find(name) ==
517 flags_ignored_because_of_predictable.end()) {
518 PrintF(
519 "%s should be added to the list of "
520 "flags_ignored_because_of_predictable\n",
521 name);
522 UNREACHABLE();
523 }
524 }
525 }
526#endif
527
528 std::string args(modified_args_as_string.str());
529 // Generate a hash that is not 0.
530 uint32_t hash = static_cast<uint32_t>(base::hash_range(
531 args.c_str(), args.c_str() + args.length())) |
532 1;
533 DCHECK_NE(hash, 0);
534 return hash;
536
537// Helper function to parse flags: Takes an argument arg and splits it into
538// a flag name and flag value (or nullptr if they are missing). negated is set
539// if the arg started with "-no" or "--no". The buffer may be used to NUL-
540// terminate the name, it must be large enough to hold any possible name.
541static void SplitArgument(const char* arg, char* buffer, int buffer_size,
542 const char** name, const char** value,
543 bool* negated) {
544 *name = nullptr;
545 *value = nullptr;
546 *negated = false;
547
548 if (arg[0] != '-') return;
549
550 // Find the begin of the flag name.
551 arg++; // remove 1st '-'
552 if (*arg == '-') {
553 arg++; // remove 2nd '-'
554 DCHECK_NE('\0', arg[0]); // '--' arguments are handled in the caller.
555 }
556 if (arg[0] == 'n' && arg[1] == 'o') {
557 arg += 2; // remove "no"
558 if (FlagHelpers::NormalizeChar(arg[0]) == '-') {
559 arg++; // remove dash after "no".
560 }
561 *negated = true;
562 }
563 *name = arg;
564
565 // Find the end of the flag name.
566 while (*arg != '\0' && *arg != '=') arg++;
567
568 // Get the value if any.
569 if (*arg == '=') {
570 // Make a copy so we can NUL-terminate the flag name.
571 size_t n = arg - *name;
572 CHECK(n < static_cast<size_t>(buffer_size)); // buffer is too small
573 MemCopy(buffer, *name, n);
574 buffer[n] = '\0';
575 *name = buffer;
576 *value = arg + 1;
577 }
578}
580template <typename T>
581bool TryParseUnsigned(Flag* flag, const char* arg, const char* value,
582 char** endp, T* out_val) {
583 // We do not use strtoul because it accepts negative numbers.
584 // Rejects values >= 2**63 when T is 64 bits wide but that
585 // seems like an acceptable trade-off.
586 uint64_t max = static_cast<uint64_t>(std::numeric_limits<T>::max());
587 errno = 0;
588 int64_t val = static_cast<int64_t>(strtoll(value, endp, 10));
589 if (val < 0 || static_cast<uint64_t>(val) > max || errno != 0) {
590 PrintF(stderr,
591 "Error: Value for flag %s of type %s is out of bounds "
592 "[0-%" PRIu64 "]\n",
593 arg, Type2String(flag->type()), max);
594 return false;
595 }
596 *out_val = static_cast<T>(val);
597 return true;
598}
599
600// static
601int FlagList::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags,
602 HelpOptions help_options) {
603 int return_code = 0;
604
605 // TODO(jgruber): Since ShouldCheckFlagContradictions looks at v8_flags
606 // values to determine whether to check for contradictions, these flag values
607 // must be available before the check returns a consistent value. That means
608 // we'd really have to add a preprocessing pass that only considers these
609 // flags (e.g. --fuzzing). Otherwise, they are position-sensitive and only
610 // disable contradiction checks for flags that come after. This is pretty
611 // surprising since no other v8 flags have such positional behavior.
613 // Parse arguments.
614 for (int i = 1; i < *argc;) {
615 int j = i; // j > 0
616 const char* arg = argv[i++];
617 if (arg == nullptr) continue;
619 // Stop processing flags on '--'.
620 if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') break;
621
622 // Split arg into flag components.
623 char buffer[1 * KB];
624 const char* name;
625 const char* value;
626 bool negated;
627 SplitArgument(arg, buffer, sizeof buffer, &name, &value, &negated);
628
629 if (name == nullptr) continue;
630
631 // Lookup the flag.
632 Flag* flag = FindFlagByName(name);
633 if (flag == nullptr) {
634 if (remove_flags) {
635 // We don't recognize this flag but since we're removing
636 // the flags we recognize we assume that the remaining flags
637 // will be processed somewhere else so this flag might make
638 // sense there.
639 continue;
640 } else {
641 PrintF(stderr, "Error: unrecognized flag %s\n", arg);
642 return_code = j;
643 break;
645 }
646
647 // If we still need a flag value, use the next argument if available.
648 if (flag->type() != Flag::TYPE_BOOL &&
649 flag->type() != Flag::TYPE_MAYBE_BOOL && value == nullptr) {
650 if (i < *argc) {
651 value = argv[i++];
652 }
653 if (!value) {
654 PrintF(stderr, "Error: missing value for flag %s of type %s\n", arg,
655 Type2String(flag->type()));
656 return_code = j;
657 break;
658 }
659 }
660
661 // Set the flag.
662 char* endp = const_cast<char*>(""); // *endp is only read
663 switch (flag->type()) {
664 case Flag::TYPE_BOOL:
665 flag->set_bool_variable(!negated, Flag::SetBy::kCommandLine);
666 break;
668 flag->set_maybe_bool_variable(!negated, Flag::SetBy::kCommandLine);
669 break;
670 case Flag::TYPE_INT:
671 flag->set_int_variable(static_cast<int>(strtol(value, &endp, 10)),
673 break;
674 case Flag::TYPE_UINT: {
675 unsigned int parsed_value;
676 if (TryParseUnsigned(flag, arg, value, &endp, &parsed_value)) {
677 flag->set_uint_variable(parsed_value, Flag::SetBy::kCommandLine);
678 } else {
679 return_code = j;
680 }
681 break;
682 }
683 case Flag::TYPE_UINT64: {
684 uint64_t parsed_value;
685 if (TryParseUnsigned(flag, arg, value, &endp, &parsed_value)) {
686 flag->set_uint64_variable(parsed_value, Flag::SetBy::kCommandLine);
687 } else {
688 return_code = j;
689 }
690 break;
691 }
692 case Flag::TYPE_FLOAT:
693 flag->set_float_variable(strtod(value, &endp),
695 break;
696 case Flag::TYPE_SIZE_T: {
697 size_t parsed_value;
698 if (TryParseUnsigned(flag, arg, value, &endp, &parsed_value)) {
699 flag->set_size_t_variable(parsed_value, Flag::SetBy::kCommandLine);
700 } else {
701 return_code = j;
702 }
703 break;
704 }
706 flag->set_string_value(value ? StrDup(value) : nullptr, true,
708 break;
709 }
710
711 // Handle errors.
712 bool is_bool_type = flag->type() == Flag::TYPE_BOOL ||
713 flag->type() == Flag::TYPE_MAYBE_BOOL;
714 if ((is_bool_type && value != nullptr) || (!is_bool_type && negated) ||
715 *endp != '\0') {
716 // TODO(neis): TryParseUnsigned may return with {*endp == '\0'} even in
717 // an error case.
718 PrintF(stderr, "Error: illegal value for flag %s of type %s\n", arg,
719 Type2String(flag->type()));
720 if (is_bool_type) {
721 PrintF(stderr,
722 "To set or unset a boolean flag, use --flag or --no-flag.\n");
723 }
724 return_code = j;
725 break;
726 }
727
728 // Remove the flag & value from the command.
729 if (remove_flags) {
730 while (j < i) {
731 argv[j++] = nullptr;
732 }
733 }
734 }
735
736 if (v8_flags.help) {
737 if (help_options.HasUsage()) {
738 PrintF(stdout, "%s", help_options.usage());
739 }
740 PrintHelp();
741 if (help_options.ShouldExit()) {
742 exit(0);
743 }
744 }
745
746 if (v8_flags.print_feature_flags_json) {
748 if (help_options.ShouldExit()) {
749 exit(0);
750 }
751 }
752
753 if (remove_flags) {
754 // Shrink the argument list.
755 int j = 1;
756 for (int i = 1; i < *argc; i++) {
757 if (argv[i] != nullptr) argv[j++] = argv[i];
758 }
759 *argc = j;
760 } else if (return_code != 0) {
761 if (return_code + 1 < *argc) {
762 PrintF(stderr, "The remaining arguments were ignored:");
763 for (int i = return_code + 1; i < *argc; ++i) {
764 PrintF(stderr, " %s", argv[i]);
765 }
766 PrintF(stderr, "\n");
767 }
768 }
769 if (return_code != 0) PrintF(stderr, "Try --help for options\n");
770
771 return return_code;
772}
773
774static char* SkipWhiteSpace(char* p) {
775 while (*p != '\0' && isspace(*p) != 0) p++;
776 return p;
777}
778
779static char* SkipBlackSpace(char* p) {
780 while (*p != '\0' && isspace(*p) == 0) p++;
781 return p;
782}
783
784// static
785int FlagList::SetFlagsFromString(const char* str, size_t len) {
786 // Make a 0-terminated copy of str.
787 std::unique_ptr<char[]> copy0{NewArray<char>(len + 1)};
788 MemCopy(copy0.get(), str, len);
789 copy0[len] = '\0';
790
791 // Strip leading white space.
792 char* copy = SkipWhiteSpace(copy0.get());
793
794 // Count the number of 'arguments'.
795 int argc = 1; // be compatible with SetFlagsFromCommandLine()
796 for (char* p = copy; *p != '\0'; argc++) {
797 p = SkipBlackSpace(p);
798 p = SkipWhiteSpace(p);
799 }
800
801 // Allocate argument array.
802 base::ScopedVector<char*> argv(argc);
803
804 // Split the flags string into arguments.
805 argc = 1; // be compatible with SetFlagsFromCommandLine()
806 for (char* p = copy; *p != '\0'; argc++) {
807 argv[argc] = p;
808 p = SkipBlackSpace(p);
809 if (*p != '\0') *p++ = '\0'; // 0-terminate argument
810 p = SkipWhiteSpace(p);
811 }
812
813 return SetFlagsFromCommandLine(&argc, argv.begin(), false);
814}
815
816// static
818 // Disallow changes via the API by setting {flags_frozen}.
819 flags_frozen.store(true, std::memory_order_relaxed);
820 // Also memory-protect the memory that holds the flag values. This makes it
821 // impossible for attackers to overwrite values, except if they find a way to
822 // first unprotect the memory again.
823 // Note that for string flags we only protect the pointer itself, but not the
824 // string storage. TODO(12887): Fix this.
826}
827
828// static
830 return flags_frozen.load(std::memory_order_relaxed);
831}
832
833// static
835 flag_hash = 0;
836 for (size_t i = 0; i < kNumFlags; ++i) {
837 flags[i].ReleaseDynamicAllocations();
838 }
839}
840
841// static
843 CpuFeatures::Probe(false);
846
847 StdoutStream os;
848 os << "The following syntax for options is accepted (both '-' and '--' are "
849 "ok):\n"
850 " --flag (bool flags only)\n"
851 " --no-flag (bool flags only)\n"
852 " --flag=value (non-bool flags only, no spaces around '=')\n"
853 " --flag value (non-bool flags only)\n"
854 " -- (captures all remaining args in JavaScript)\n\n";
855 os << "Options:\n";
856
857 for (const Flag& f : flags) {
858 os << " " << FlagName{f.name()} << " (" << f.comment() << ")\n"
859 << " type: " << Type2String(f.type()) << " default: " << f
860 << "\n";
861 }
862}
863
864// static
866 StdoutStream os;
867 for (const Flag& f : flags) {
868 os << f << "\n";
869 }
870}
871
872namespace {
873
874void PrintFlagsJSONArray(std::ostream& os,
875 const std::vector<const char*>& flags) {
876 if (flags.empty()) {
877 os << "[]";
878 } else {
879 os << "[\n";
880 bool first = true;
881 for (const auto& flag : flags) {
882 if (!first) os << ",\n";
883 os << " \"" << flag << "\"";
884 first = false;
885 }
886 os << "\n" << " ]";
887 }
888}
889
890void PrintFeatureFlagsJSONObject(
891 std::ostream& os, const std::vector<const char*>& inprogress_flags,
892 const std::vector<const char*>& staged_flags,
893 const std::vector<const char*>& shipping_flags) {
894 os << "{\n";
895
896 os << " \"in-progress\": ";
897 PrintFlagsJSONArray(os, inprogress_flags);
898 os << ",\n";
899
900 os << " \"staged\": ";
901 PrintFlagsJSONArray(os, staged_flags);
902 os << ",\n";
903
904 os << " \"shipping\": ";
905 PrintFlagsJSONArray(os, shipping_flags);
906 os << "\n";
907
908 os << " }";
909}
910
911} // namespace
912
913// static
915 StdoutStream os;
916
917 os << "{\n";
918
919 {
920 std::vector<const char*> inprogress_flags;
921 std::vector<const char*> staged_flags;
922 std::vector<const char*> shipping_flags;
923
924#define ADD_JS_INPROGRESS_FLAG(name, desc) inprogress_flags.push_back(#name);
925#define ADD_JS_STAGED_FLAG(name, desc) staged_flags.push_back(#name);
926#define ADD_JS_SHIPPING_FLAG(name, desc) shipping_flags.push_back(#name);
927
931
932 os << " \"js\": ";
933 PrintFeatureFlagsJSONObject(os, inprogress_flags, staged_flags,
934 shipping_flags);
935 os << ",\n";
936 }
937
938 {
939 std::vector<const char*> inprogress_flags;
940 std::vector<const char*> staged_flags;
941 std::vector<const char*> shipping_flags;
942
946
947 os << " \"harmony\": ";
948 PrintFeatureFlagsJSONObject(os, inprogress_flags, staged_flags,
949 shipping_flags);
950 os << ",\n";
951 }
952
953#if V8_ENABLE_WEBASSEMBLY
954 {
955 std::vector<const char*> inprogress_flags;
956 std::vector<const char*> staged_flags;
957 std::vector<const char*> shipping_flags;
958
959#define ADD_WASM_INPROGRESS_FLAG(name, desc, val) \
960 inprogress_flags.push_back("experimental_wasm_" #name);
961#define ADD_WASM_STAGED_FLAG(name, desc, val) \
962 staged_flags.push_back("experimental_wasm_" #name);
963#define ADD_WASM_SHIPPED_FLAG(name, desc, val) \
964 shipping_flags.push_back("experimental_wasm_" #name);
965
966 FOREACH_WASM_EXPERIMENTAL_FEATURE_FLAG(ADD_WASM_INPROGRESS_FLAG)
967 FOREACH_WASM_STAGING_FEATURE_FLAG(ADD_WASM_STAGED_FLAG)
968 FOREACH_WASM_SHIPPED_FEATURE_FLAG(ADD_WASM_SHIPPED_FLAG)
969
970 os << " \"wasm\": ";
971 PrintFeatureFlagsJSONObject(os, inprogress_flags, staged_flags,
972 shipping_flags);
973 os << "\n";
974 }
975#endif // V8_ENABLE_WEBASSEMBLY
976
977 os << "}\n";
978
979#undef ADD_JS_INPROGRESS_FLAG
980#undef ADD_JS_STAGED_FLAG
981#undef ADD_JS_SHIPPING_FLAG
982#undef ADD_WASM_INPROGRESS_FLAG
983#undef ADD_WASM_STAGED_FLAG
984#undef ADD_WASM_SHIPPED_FLAG
985}
986
987namespace {
988
989class ImplicationProcessor {
990 public:
991 // Returns {true} if any flag value was changed.
992 bool EnforceImplications() {
993 bool changed = false;
994#define FLAG_MODE_DEFINE_IMPLICATIONS
995#include "src/flags/flag-definitions.h" // NOLINT(build/include)
996#undef FLAG_MODE_DEFINE_IMPLICATIONS
997 CheckForCycle();
998 return changed;
999 }
1000
1001 private:
1002 // Called from {DEFINE_*_IMPLICATION} in flag-definitions.h.
1003 template <class T>
1004 bool TriggerImplication(bool premise, const char* premise_name,
1005 FlagValue<T>* conclusion_value,
1006 const char* conclusion_name, T value,
1007 bool weak_implication) {
1008 if (!premise) return false;
1009 Flag* conclusion_flag = FindImplicationFlagByName(conclusion_name);
1010 if (!conclusion_flag->CheckFlagChange(
1011 weak_implication ? Flag::SetBy::kWeakImplication
1013 conclusion_value->value() != value, premise_name)) {
1014 return false;
1015 }
1016 if (V8_UNLIKELY(num_iterations_ >= kMaxNumIterations)) {
1017 cycle_ << "\n" << FlagName{premise_name} << " -> ";
1018 if constexpr (std::is_same_v<T, bool>) {
1019 cycle_ << FlagName{conclusion_flag->name(), !value};
1020 } else {
1021 cycle_ << FlagName{conclusion_flag->name()} << " = " << value;
1022 }
1023 }
1024 *conclusion_value = value;
1025 return true;
1026 }
1027
1028 // Called from {DEFINE_*_IMPLICATION} in flag-definitions.h, when the
1029 // conclusion flag is read-only (note this is the const overload of the
1030 // function just above).
1031 template <class T>
1032 bool TriggerImplication(bool premise, const char* premise_name,
1033 const FlagValue<T>* conclusion_value,
1034 const char* conclusion_name, T value,
1035 bool weak_implication) {
1036 if (!premise) return false;
1037 Flag* conclusion_flag = FindImplicationFlagByName(conclusion_name);
1038 // Because this is the `const FlagValue*` overload:
1039 DCHECK(conclusion_flag->IsReadOnly());
1040 if (!conclusion_flag->CheckFlagChange(
1041 weak_implication ? Flag::SetBy::kWeakImplication
1043 conclusion_value->value() != value, premise_name)) {
1044 return false;
1045 }
1046 // Must equal the default value, otherwise CheckFlagChange should've
1047 // returned false.
1048 DCHECK_EQ(value, conclusion_flag->GetDefaultValue<T>());
1049 return true;
1050 }
1051
1052 void CheckForCycle() {
1053 // Make sure flag implications reach a fixed point within
1054 // {kMaxNumIterations} iterations.
1055 if (++num_iterations_ < kMaxNumIterations) return;
1056
1057 if (num_iterations_ == kMaxNumIterations) {
1058 // Start cycle detection.
1059 DCHECK(cycle_.str().empty());
1061 return;
1062 }
1063
1064 DCHECK_NE(0, cycle_start_hash_);
1065 // We accept spurious but highly unlikely hash collisions here. This is
1066 // only a debug output anyway.
1067 if (ComputeFlagListHash() == cycle_start_hash_) {
1068 DCHECK(!cycle_.str().empty());
1069 // {cycle_} starts with a newline.
1070 FATAL("Cycle in flag implications:%s", cycle_.str().c_str());
1071 }
1072 // We must have found a cycle within another {kMaxNumIterations}.
1073 DCHECK_GE(2 * kMaxNumIterations, num_iterations_);
1074 }
1075
1076 static constexpr size_t kMaxNumIterations = kNumFlags;
1078 // After {kMaxNumIterations} we use the following two fields for finding
1079 // cycles in flags.
1081 std::ostringstream cycle_;
1082};
1083
1084} // namespace
1085
1086// Defines a contradicion if at least one of the two flags is set. We currently
1087// don't handle contradictions when two default-on flags are turned off, because
1088// there are none.
1089#define CONTRADICTION(flag1, flag2) \
1090 (v8_flags.flag1 || v8_flags.flag2) \
1091 ? std::make_tuple(FindFlagByPointer(&v8_flags.flag1), \
1092 FindFlagByPointer(&v8_flags.flag2)) \
1093 : std::make_tuple(nullptr, nullptr)
1094
1095#define RESET_WHEN_FUZZING(flag) CONTRADICTION(flag, fuzzing)
1096#define RESET_WHEN_CORRECTNESS_FUZZING(flag) \
1097 CONTRADICTION(flag, correctness_fuzzer_suppressions)
1098
1099// static
1101 if (!i::v8_flags.fuzzing) return;
1102
1103 std::tuple<Flag*, Flag*> contradictions[] = {
1104 // List of flags that lead to known contradictory cycles when both
1105 // deviate from their defaults. One of them will be reset with precedence
1106 // left to right.
1107 CONTRADICTION(always_osr_from_maglev, disable_optimizing_compilers),
1108 CONTRADICTION(always_osr_from_maglev, jitless),
1109 CONTRADICTION(always_osr_from_maglev, lite_mode),
1110 CONTRADICTION(always_osr_from_maglev, turbofan),
1111 CONTRADICTION(always_osr_from_maglev, turboshaft),
1112 CONTRADICTION(always_turbofan, disable_optimizing_compilers),
1113 CONTRADICTION(always_turbofan, jitless),
1114 CONTRADICTION(always_turbofan, lite_mode),
1115 CONTRADICTION(always_turbofan, turboshaft),
1116 CONTRADICTION(assert_types, stress_concurrent_inlining),
1117 CONTRADICTION(assert_types, stress_concurrent_inlining_attach_code),
1118 CONTRADICTION(disable_optimizing_compilers, maglev_future),
1119 CONTRADICTION(disable_optimizing_compilers, stress_concurrent_inlining),
1120 CONTRADICTION(disable_optimizing_compilers,
1121 stress_concurrent_inlining_attach_code),
1122 CONTRADICTION(disable_optimizing_compilers, stress_maglev),
1123 CONTRADICTION(disable_optimizing_compilers,
1124 turboshaft_wasm_in_js_inlining),
1125 CONTRADICTION(jitless, maglev_future),
1126 CONTRADICTION(jitless, stress_concurrent_inlining),
1127 CONTRADICTION(jitless, stress_concurrent_inlining_attach_code),
1128 CONTRADICTION(jitless, stress_maglev),
1129 CONTRADICTION(lite_mode, maglev_future),
1130 CONTRADICTION(lite_mode, predictable_gc_schedule),
1131 CONTRADICTION(lite_mode, stress_concurrent_inlining),
1132 CONTRADICTION(lite_mode, stress_concurrent_inlining_attach_code),
1133 CONTRADICTION(lite_mode, stress_maglev),
1134 CONTRADICTION(optimize_for_size, predictable_gc_schedule),
1135 CONTRADICTION(predictable, stress_concurrent_inlining_attach_code),
1136 CONTRADICTION(predictable_gc_schedule, stress_compaction),
1137 CONTRADICTION(single_threaded, stress_concurrent_inlining_attach_code),
1138 CONTRADICTION(stress_concurrent_inlining, turboshaft_assert_types),
1139 CONTRADICTION(stress_concurrent_inlining_attach_code,
1140 turboshaft_assert_types),
1141 CONTRADICTION(turboshaft, stress_concurrent_inlining),
1142 CONTRADICTION(turboshaft, stress_concurrent_inlining_attach_code),
1143
1144 // List of flags that shouldn't be used when --fuzzing or
1145 // --correctness-fuzzer-suppressions is passed. These flags will be reset
1146 // to their defaults.
1147
1148 // https://crbug.com/369652671
1149 RESET_WHEN_CORRECTNESS_FUZZING(stress_lazy_compilation),
1150
1151 // https://crbug.com/380327159
1152 RESET_WHEN_CORRECTNESS_FUZZING(turbo_stats),
1153 RESET_WHEN_CORRECTNESS_FUZZING(turbo_stats_nvp),
1154 RESET_WHEN_CORRECTNESS_FUZZING(turbo_stats_wasm),
1155
1156 // https://crbug.com/369974230
1157 RESET_WHEN_FUZZING(expose_async_hooks),
1159 // https://crbug.com/371061101
1160 RESET_WHEN_FUZZING(parallel_compile_tasks_for_lazy),
1162 // https://crbug.com/366671002
1163 RESET_WHEN_FUZZING(stress_snapshot),
1164 };
1165 for (auto [flag1, flag2] : contradictions) {
1166 if (!flag1 || !flag2) continue;
1167 if (flag1->IsDefault() || flag2->IsDefault()) continue;
1169 // Ensure we never reset the fuzzing flags.
1170 CHECK(!flag1->PointsTo(&v8_flags.fuzzing));
1171 CHECK(!flag1->PointsTo(&v8_flags.correctness_fuzzer_suppressions));
1173 std::cerr << "Warning: resetting flag --" << flag1->name()
1174 << " due to conflicting flags" << std::endl;
1175 flag1->Reset();
1177 if ((v8_flags.trace_turbo || v8_flags.trace_turbo_graph) &&
1178 v8_flags.fuzzing_and_concurrent_recompilation) {
1179 std::cerr
1180 << "Use --nofuzzing-and-concurrent-recompilation to force "
1181 "enable --trace-turbo, and friends. This is not thread-safe.\n";
1182 }
1183}
1184
1185#undef CONTRADICTION
1186
1187// static
1189 for (ImplicationProcessor proc; proc.EnforceImplications();) {
1190 // Continue processing (recursive) implications. The processor has an
1191 // internal limit to avoid endless recursion.
1192 }
1193}
1195// static
1196uint32_t FlagList::Hash() {
1197 if (uint32_t hash = flag_hash.load(std::memory_order_relaxed)) return hash;
1198 uint32_t hash = ComputeFlagListHash();
1199 flag_hash.store(hash, std::memory_order_relaxed);
1200 return hash;
1201}
1202
1203// static
1205 // If flags are frozen, we should not need to reset the hash since we cannot
1206 // change flag values anyway.
1207 CHECK(!IsFrozen());
1209}
1210
1211} // namespace v8::internal
constexpr int kMinimumOSPageSize
static void ExitProcess(int exit_code)
static void SetDataReadOnly(void *address, size_t size)
constexpr T * begin() const
Definition vector.h:96
static void Probe(bool cross_compile)
static bool EqualNames(const char *a, const char *b)
static char NormalizeChar(char ch)
static int FlagNamesCmp(const char *a, const char *b)
static bool EqualNameWithSuffix(const char *a, const char *b)
static int SetFlagsFromString(const char *str, size_t len)
Definition flags.cc:785
static uint32_t Hash()
Definition flags.cc:1196
static bool IsFrozen()
Definition flags.cc:829
static void EnforceFlagImplications()
Definition flags.cc:1188
static void PrintValues()
Definition flags.cc:865
static int SetFlagsFromCommandLine(int *argc, char **argv, bool remove_flags, FlagList::HelpOptions help_options=FlagList::HelpOptions())
Definition flags.cc:601
static void ReleaseDynamicAllocations()
Definition flags.cc:834
static void PrintFeatureFlagsJSON()
Definition flags.cc:914
static void PrintHelp()
Definition flags.cc:842
static void ResolveContradictionsWhenFuzzing()
Definition flags.cc:1100
static void ResetFlagHash()
Definition flags.cc:1204
static void FreezeFlags()
Definition flags.cc:817
Flag * GetFlag(const char *name)
Definition flags.cc:329
std::array< Flag *, kNumFlags > flags_
Definition flags.cc:337
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
#define DEBUG_BOOL
Definition globals.h:87
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
#define JAVASCRIPT_INPROGRESS_FEATURES(V)
#define HARMONY_SHIPPING(V)
#define JAVASCRIPT_STAGED_FEATURES(V)
#define HARMONY_INPROGRESS(V)
#define JAVASCRIPT_SHIPPING_FEATURES(V)
#define HARMONY_STAGED(V)
static constexpr size_t kMaxNumIterations
Definition flags.cc:1076
size_t num_iterations_
Definition flags.cc:1077
#define ADD_JS_STAGED_FLAG(name, desc)
std::ostringstream cycle_
Definition flags.cc:1081
#define RESET_WHEN_FUZZING(flag)
Definition flags.cc:1095
#define CONTRADICTION(flag1, flag2)
Definition flags.cc:1089
#define ADD_JS_INPROGRESS_FLAG(name, desc)
#define ADD_JS_SHIPPING_FLAG(name, desc)
uint32_t cycle_start_hash_
Definition flags.cc:1080
#define RESET_WHEN_CORRECTNESS_FUZZING(flag)
Definition flags.cc:1096
#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName,...)
int n
Definition mul-fft.cc:296
V8_INLINE size_t hash_range(Iterator first, Iterator last)
Definition hashing.h:308
constexpr Vector< T > ArrayVector(T(&arr)[N])
Definition vector.h:354
void DeleteArray(T *array)
Definition allocation.h:63
bool check_implications
Definition flags.cc:3668
V8_EXPORT_PRIVATE base::Vector< Flag > Flags()
Definition flags.cc:300
V8_EXPORT_PRIVATE Flag * FindFlagByName(const char *name)
Definition flags.cc:353
return change_flag
Definition flags.cc:3733
constexpr size_t kNumFlags
Definition flags.cc:298
void PrintF(const char *format,...)
Definition utils.cc:39
Flag * FindFlagByPointer(const void *ptr)
Definition flags.cc:369
static void SplitArgument(const char *arg, char *buffer, int buffer_size, const char **name, const char **value, bool *negated)
Definition flags.cc:541
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
static char * SkipWhiteSpace(char *p)
Definition flags.cc:774
std::ostream & operator<<(std::ostream &os, AtomicMemoryOrder order)
bool is_bool_flag
Definition flags.cc:3667
static std::atomic< uint32_t > flag_hash
Definition flags.cc:446
char * StrDup(const char *str)
static char * SkipBlackSpace(char *p)
Definition flags.cc:779
bool TryParseUnsigned(Flag *flag, const char *arg, const char *value, char **endp, T *out_val)
Definition flags.cc:581
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation trace turbo cfg trace TurboFan s graph trimmer trace TurboFan s control equivalence trace TurboFan s register allocator trace stack load store counters for optimized code in run fuzzing &&concurrent_recompilation trace_turbo trace_turbo_scheduled trace_turbo_stack_accesses verify TurboFan machine graph of code stubs enable FixedArray bounds checks print TurboFan statistics of wasm compilations maximum cumulative size of bytecode considered for inlining scale factor of bytecode size used to calculate the inlining budget * KB
Definition flags.cc:1366
static const char * Type2String(Flag::FlagType type)
Definition flags.cc:376
V8_EXPORT_PRIVATE FlagValues v8_flags
V8_EXPORT_PRIVATE Flag * FindImplicationFlagByName(const char *name)
Definition flags.cc:344
return value
Definition map-inl.h:893
static std::atomic< bool > flags_frozen
Definition flags.cc:447
FlagValues v8_flags PERMISSION_MUTABLE_SECTION
Definition flags.cc:38
void MemCopy(void *dest, const void *src, size_t size)
Definition memcopy.h:124
uint32_t ComputeFlagListHash()
Definition flags.cc:449
T * NewArray(size_t size)
Definition allocation.h:43
#define MSVC_SUPPRESS_WARNING(n)
#define FATAL(...)
Definition logging.h:47
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define arraysize(array)
Definition macros.h:67
bool operator()(const Flag *a, const Flag *b) const
Definition flags.cc:303
bool operator()(const Flag *a, const char *b) const
Definition flags.cc:309
void set_bool_variable(bool value, SetBy set_by)
Definition flags-impl.h:110
uint64_t uint64_default() const
Definition flags-impl.h:181
double float_variable() const
Definition flags-impl.h:142
int int_variable() const
Definition flags-impl.h:122
std::optional< bool > maybe_bool_variable() const
Definition flags-impl.h:114
double float_default() const
Definition flags-impl.h:186
V8_EXPORT_PRIVATE void Reset()
Definition flags.cc:3768
const char * string_value() const
Definition flags-impl.h:154
int int_default() const
Definition flags-impl.h:171
const char * name() const
Definition flags-impl.h:88
size_t size_t_default() const
Definition flags-impl.h:191
void set_uint64_variable(uint64_t value, SetBy set_by)
Definition flags-impl.h:138
void set_size_t_variable(size_t value, SetBy set_by)
Definition flags-impl.h:150
bool bool_variable() const
Definition flags-impl.h:108
const char * implied_by_
Definition flags-impl.h:80
bool bool_default() const
Definition flags-impl.h:166
void set_float_variable(double value, SetBy set_by)
Definition flags-impl.h:144
bool IsDefault() const
Definition flags.cc:3736
unsigned int uint_variable() const
Definition flags-impl.h:128
size_t size_t_variable() const
Definition flags-impl.h:148
constexpr bool IsAnyImplication(Flag::SetBy set_by)
Definition flags-impl.h:68
void set_maybe_bool_variable(std::optional< bool > value, SetBy set_by)
Definition flags-impl.h:118
void set_uint_variable(unsigned int value, SetBy set_by)
Definition flags-impl.h:132
bool IsReadOnly() const
Definition flags-impl.h:210
void ReleaseDynamicAllocations()
Definition flags.cc:3763
void set_string_value(const char *new_value, bool owns_new_value, SetBy set_by)
unsigned int uint_default() const
Definition flags-impl.h:176
bool CheckFlagChange(SetBy new_set_by, bool change_flag, const char *implied_by=nullptr)
void set_int_variable(int value, SetBy set_by)
Definition flags-impl.h:124
static bool ShouldCheckFlagContradictions()
uint64_t uint64_variable() const
Definition flags-impl.h:136
const char * string_default() const
Definition flags-impl.h:196
#define V8_UNLIKELY(condition)
Definition v8config.h:660
#define FOREACH_WASM_STAGING_FEATURE_FLAG(V)
#define FOREACH_WASM_SHIPPED_FEATURE_FLAG(V)
#define FOREACH_WASM_EXPERIMENTAL_FEATURE_FLAG(V)