Commit dc18b822 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

Reland^3 "[flags] warn about contradictory flags"

This is a reland of 0ba115e6
Changes:
- Also allow second parameter influenced by --cache to be reassigned.
- Fix --stress-opt to only --always-opt in the last iteration as before.

Original change's description:
> Reland^2 "[flags] warn about contradictory flags"
>
> This is a reland of d8f8a7e2
> Change compared to last reland:
> - Do not check for d8 flag contradictions in the presence of --fuzzing
> - Allow identical re-declaration of --cache=*
>
> Original change's description:
> > Reland "[flags] warn about contradictory flags"
> >
> > This is a reland of b8f91666
> > Difference to previous CL: Additional functionality to specify
> > incompatible flags based on GN variables and extra-flags, used
> > to fix the issues that came up on the waterfall.
> >
> > This also changes the rules regarding repeated flags: While
> > explicitly repeated flags are allowed for boolean values as long
> > as they are identical, repeated flags or explicit flags in the
> > presence of an active implication are disallowed for non-boolean
> > flags. The latter simplifies specifying conflict rules in
> > variants.py. Otherwise a rule like
> >
> > INCOMPATIBLE_FLAGS_PER_EXTRA_FLAG = {
> >   "--gc-interval=*": ["--gc-interval=*"],
> > }
> >
> > wouldn't work because specifying the same GC interval twice
> > wouldn't actually count as a conflict. This was an issue with
> > test/mjsunit/wasm/gc-buffer.js, which specifies
> > --gc-interval=500 exactly like the extra flag by the stress bot.
> >
> > Also, this now expands contradictory flags checking to d8 flags
> > for consistency.
> >
> > Original change's description:
> > > [flags] warn about contradictory flags
> > >
> > > Design Doc: https://docs.google.com/document/d/1lkvu8crkK7Ei39qjkPCFijpNyxWXsOktG9GB-7K34jM/
> > >
> > > Bug: v8:10577
> > > Change-Id: Ib9cfdffa401c48c895bf31caed5ee03545beddab
> > > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2154792
> > > Reviewed-by: Clemens Backes <clemensb@chromium.org>
> > > Reviewed-by: Michael Achenbach <machenbach@chromium.org>
> > > Reviewed-by: Georg Neis <neis@chromium.org>
> > > Reviewed-by: Tamer Tas <tmrts@chromium.org>
> > > Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
> > > Cr-Commit-Position: refs/heads/master@{#68168}
> >
> > Bug: v8:10577
> > Change-Id: I268e590ee18a535b13dee14eeb15ddd0a9ee8341
> > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2235115
> > Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
> > Reviewed-by: Tamer Tas <tmrts@chromium.org>
> > Reviewed-by: Clemens Backes <clemensb@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#68989}
>
> Bug: v8:10577
> Change-Id: I31d2794d4f9ff630f3444210100c64d67d881276
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2339464
> Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
> Reviewed-by: Clemens Backes <clemensb@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#69339}

Bug: v8:10577
Cq-Include-Trybots: luci.v8.try:v8_linux64_tsan_rel_ng
Cq-Include-Trybots: luci.v8.try:v8_linux64_tsan_isolates_rel_ng
Change-Id: I4a69dc57a102782cb453144323e3752ac8278624
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2352770
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69433}
parent 46dac207
...@@ -677,7 +677,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) { ...@@ -677,7 +677,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) {
if (connect(sockfd, reinterpret_cast<sockaddr*>(&serv_addr), if (connect(sockfd, reinterpret_cast<sockaddr*>(&serv_addr),
sizeof(serv_addr)) < 0) { sizeof(serv_addr)) < 0) {
fprintf(stderr, "Failed to connect to localhost:%d\n", fprintf(stderr, "Failed to connect to localhost:%d\n",
Shell::options.read_from_tcp_port); Shell::options.read_from_tcp_port.get());
close(sockfd); close(sockfd);
return nullptr; return nullptr;
} }
...@@ -705,7 +705,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) { ...@@ -705,7 +705,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) {
ssize_t sent_now = send(sockfd, name + sent_len, name_len - sent_len, 0); ssize_t sent_now = send(sockfd, name + sent_len, name_len - sent_len, 0);
if (sent_now < 0) { if (sent_now < 0) {
fprintf(stderr, "Failed to send %s to localhost:%d\n", name, fprintf(stderr, "Failed to send %s to localhost:%d\n", name,
Shell::options.read_from_tcp_port); Shell::options.read_from_tcp_port.get());
close(sockfd); close(sockfd);
return nullptr; return nullptr;
} }
...@@ -722,7 +722,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) { ...@@ -722,7 +722,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) {
// We need those 4 bytes to read off the file length. // We need those 4 bytes to read off the file length.
if (received < 4) { if (received < 4) {
fprintf(stderr, "Failed to receive %s's length from localhost:%d\n", name, fprintf(stderr, "Failed to receive %s's length from localhost:%d\n", name,
Shell::options.read_from_tcp_port); Shell::options.read_from_tcp_port.get());
close(sockfd); close(sockfd);
return nullptr; return nullptr;
} }
...@@ -731,7 +731,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) { ...@@ -731,7 +731,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) {
if (file_length < 0) { if (file_length < 0) {
fprintf(stderr, "Received length %d for %s from localhost:%d\n", fprintf(stderr, "Received length %d for %s from localhost:%d\n",
file_length, name, Shell::options.read_from_tcp_port); file_length, name, Shell::options.read_from_tcp_port.get());
close(sockfd); close(sockfd);
return nullptr; return nullptr;
} }
...@@ -746,7 +746,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) { ...@@ -746,7 +746,7 @@ char* Shell::ReadCharsFromTcpPort(const char* name, int* size_out) {
recv(sockfd, chars + total_received, file_length - total_received, 0); recv(sockfd, chars + total_received, file_length - total_received, 0);
if (received < 0) { if (received < 0) {
fprintf(stderr, "Failed to receive %s from localhost:%d\n", name, fprintf(stderr, "Failed to receive %s from localhost:%d\n", name,
Shell::options.read_from_tcp_port); Shell::options.read_from_tcp_port.get());
close(sockfd); close(sockfd);
delete[] chars; delete[] chars;
return nullptr; return nullptr;
......
...@@ -472,6 +472,7 @@ std::atomic<int> Shell::unhandled_promise_rejections_{0}; ...@@ -472,6 +472,7 @@ std::atomic<int> Shell::unhandled_promise_rejections_{0};
Global<Context> Shell::evaluation_context_; Global<Context> Shell::evaluation_context_;
ArrayBuffer::Allocator* Shell::array_buffer_allocator; ArrayBuffer::Allocator* Shell::array_buffer_allocator;
bool check_d8_flag_contradictions = true;
ShellOptions Shell::options; ShellOptions Shell::options;
base::OnceType Shell::quit_once_ = V8_ONCE_INIT; base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
...@@ -3233,6 +3234,7 @@ void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -3233,6 +3234,7 @@ void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
bool Shell::SetOptions(int argc, char* argv[]) { bool Shell::SetOptions(int argc, char* argv[]) {
bool logfile_per_isolate = false; bool logfile_per_isolate = false;
bool no_always_opt = false;
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], "--") == 0) { if (strcmp(argv[i], "--") == 0) {
argv[i] = nullptr; argv[i] = nullptr;
...@@ -3260,8 +3262,9 @@ bool Shell::SetOptions(int argc, char* argv[]) { ...@@ -3260,8 +3262,9 @@ bool Shell::SetOptions(int argc, char* argv[]) {
argv[i] = nullptr; argv[i] = nullptr;
} else if (strcmp(argv[i], "--noalways-opt") == 0 || } else if (strcmp(argv[i], "--noalways-opt") == 0 ||
strcmp(argv[i], "--no-always-opt") == 0) { strcmp(argv[i], "--no-always-opt") == 0) {
// No support for stressing if we can't use --always-opt. no_always_opt = true;
options.stress_opt = false; } else if (strcmp(argv[i], "--fuzzing") == 0) {
check_d8_flag_contradictions = false;
} else if (strcmp(argv[i], "--logfile-per-isolate") == 0) { } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
logfile_per_isolate = true; logfile_per_isolate = true;
argv[i] = nullptr; argv[i] = nullptr;
...@@ -3402,6 +3405,10 @@ bool Shell::SetOptions(int argc, char* argv[]) { ...@@ -3402,6 +3405,10 @@ bool Shell::SetOptions(int argc, char* argv[]) {
} }
} }
if (options.stress_opt && no_always_opt) {
FATAL("Flag --no-always-opt is incompatible with --stress-opt.");
}
const char* usage = const char* usage =
"Synopsis:\n" "Synopsis:\n"
" shell [options] [--shell] [<file>...]\n" " shell [options] [--shell] [<file>...]\n"
...@@ -3410,6 +3417,7 @@ bool Shell::SetOptions(int argc, char* argv[]) { ...@@ -3410,6 +3417,7 @@ bool Shell::SetOptions(int argc, char* argv[]) {
" --shell run an interactive JavaScript shell\n" " --shell run an interactive JavaScript shell\n"
" --module execute a file as a JavaScript module\n\n"; " --module execute a file as a JavaScript module\n\n";
using HelpOptions = i::FlagList::HelpOptions; using HelpOptions = i::FlagList::HelpOptions;
i::FLAG_abort_on_contradictory_flags = true;
i::FlagList::SetFlagsFromCommandLine(&argc, argv, true, i::FlagList::SetFlagsFromCommandLine(&argc, argv, true,
HelpOptions(HelpOptions::kExit, usage)); HelpOptions(HelpOptions::kExit, usage));
options.mock_arraybuffer_allocator = i::FLAG_mock_arraybuffer_allocator; options.mock_arraybuffer_allocator = i::FLAG_mock_arraybuffer_allocator;
...@@ -3870,12 +3878,11 @@ class D8Testing { ...@@ -3870,12 +3878,11 @@ class D8Testing {
"--max-inlined-bytecode-size=999999 " "--max-inlined-bytecode-size=999999 "
"--max-inlined-bytecode-size-cumulative=999999 " "--max-inlined-bytecode-size-cumulative=999999 "
"--noalways-opt"; "--noalways-opt";
static const char* kForcedOptimizations = "--always-opt";
if (run == GetStressRuns() - 1) { if (run == 0) {
V8::SetFlagsFromString(kForcedOptimizations);
} else {
V8::SetFlagsFromString(kLazyOptimizations); V8::SetFlagsFromString(kLazyOptimizations);
} else if (run == GetStressRuns() - 1) {
i::FLAG_always_opt = true;
} }
} }
...@@ -4117,7 +4124,7 @@ int Shell::Main(int argc, char* argv[]) { ...@@ -4117,7 +4124,7 @@ int Shell::Main(int argc, char* argv[]) {
options.stress_runs = D8Testing::GetStressRuns(); options.stress_runs = D8Testing::GetStressRuns();
for (int i = 0; i < options.stress_runs && result == 0; i++) { for (int i = 0; i < options.stress_runs && result == 0; i++) {
printf("============ Stress %d/%d ============\n", i + 1, printf("============ Stress %d/%d ============\n", i + 1,
options.stress_runs); options.stress_runs.get());
D8Testing::PrepareStressRun(i); D8Testing::PrepareStressRun(i);
bool last_run = i == options.stress_runs - 1; bool last_run = i == options.stress_runs - 1;
result = RunMain(isolate, last_run); result = RunMain(isolate, last_run);
...@@ -4128,7 +4135,7 @@ int Shell::Main(int argc, char* argv[]) { ...@@ -4128,7 +4135,7 @@ int Shell::Main(int argc, char* argv[]) {
options.stress_runs = i::FLAG_stress_runs; options.stress_runs = i::FLAG_stress_runs;
for (int i = 0; i < options.stress_runs && result == 0; i++) { for (int i = 0; i < options.stress_runs && result == 0; i++) {
printf("============ Run %d/%d ============\n", i + 1, printf("============ Run %d/%d ============\n", i + 1,
options.stress_runs); options.stress_runs.get());
bool last_run = i == options.stress_runs - 1; bool last_run = i == options.stress_runs - 1;
result = RunMain(isolate, last_run); result = RunMain(isolate, last_run);
} }
...@@ -4155,14 +4162,16 @@ int Shell::Main(int argc, char* argv[]) { ...@@ -4155,14 +4162,16 @@ int Shell::Main(int argc, char* argv[]) {
DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile || DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile ||
options.compile_options == options.compile_options ==
v8::ScriptCompiler::kNoCompileOptions); v8::ScriptCompiler::kNoCompileOptions);
options.compile_options = v8::ScriptCompiler::kConsumeCodeCache; options.compile_options.Overwrite(
options.code_cache_options = v8::ScriptCompiler::kConsumeCodeCache);
ShellOptions::CodeCacheOptions::kNoProduceCache; options.code_cache_options.Overwrite(
ShellOptions::CodeCacheOptions::kNoProduceCache);
printf("============ Run: Consume code cache ============\n"); printf("============ Run: Consume code cache ============\n");
// Second run to consume the cache in current isolate // Second run to consume the cache in current isolate
result = RunMain(isolate, true); result = RunMain(isolate, true);
options.compile_options = v8::ScriptCompiler::kNoCompileOptions; options.compile_options.Overwrite(
v8::ScriptCompiler::kNoCompileOptions);
} else { } else {
bool last_run = true; bool last_run = true;
result = RunMain(isolate, last_run); result = RunMain(isolate, last_run);
......
...@@ -282,6 +282,8 @@ class PerIsolateData { ...@@ -282,6 +282,8 @@ class PerIsolateData {
int RealmFind(Local<Context> context); int RealmFind(Local<Context> context);
}; };
extern bool check_d8_flag_contradictions;
class ShellOptions { class ShellOptions {
public: public:
enum CodeCacheOptions { enum CodeCacheOptions {
...@@ -292,47 +294,97 @@ class ShellOptions { ...@@ -292,47 +294,97 @@ class ShellOptions {
~ShellOptions() { delete[] isolate_sources; } ~ShellOptions() { delete[] isolate_sources; }
bool fuzzilli_coverage_statistics = false; // In analogy to Flag::CheckFlagChange() in src/flags/flag.cc, only allow
bool fuzzilli_enable_builtins_coverage = true; // repeated flags for identical boolean values. We allow exceptions for flags
bool send_idle_notification = false; // with enum-like arguments since their conflicts can also be specified
bool invoke_weak_callbacks = false; // completely.
bool omit_quit = false; template <class T,
bool wait_for_background_tasks = true; bool kAllowIdenticalAssignment = std::is_same<T, bool>::value>
bool stress_opt = false; class DisallowReassignment {
int stress_runs = 1; public:
bool stress_snapshot = false; DisallowReassignment(const char* name, T value)
bool interactive_shell = false; : name_(name), value_(value) {}
operator T() const { return value_; } // NOLINT
T get() const { return value_; }
DisallowReassignment& operator=(T value) {
if (check_d8_flag_contradictions) {
if (kAllowIdenticalAssignment) {
if (specified_ && value_ != value) {
FATAL("Contradictory values for d8 flag --%s", name_);
}
} else {
if (specified_) {
FATAL("Repeated specification of d8 flag --%s", name_);
}
}
}
value_ = value;
specified_ = true;
return *this;
}
void Overwrite(T value) { value_ = value; }
private:
const char* name_;
T value_;
bool specified_ = false;
};
DisallowReassignment<bool> fuzzilli_coverage_statistics = {
"fuzzilli-coverage-statistics", false};
DisallowReassignment<bool> fuzzilli_enable_builtins_coverage = {
"fuzzilli-enable-builtins-coverage", true};
DisallowReassignment<bool> send_idle_notification = {"send-idle-notification",
false};
DisallowReassignment<bool> invoke_weak_callbacks = {"invoke-weak-callbacks",
false};
DisallowReassignment<bool> omit_quit = {"omit-quit", false};
DisallowReassignment<bool> wait_for_background_tasks = {
"wait-for-background-tasks", true};
DisallowReassignment<bool> stress_opt = {"stress-opt", false};
DisallowReassignment<int> stress_runs = {"stress-runs", 1};
DisallowReassignment<bool> stress_snapshot = {"stress-snapshot", false};
DisallowReassignment<bool> interactive_shell = {"shell", false};
bool test_shell = false; bool test_shell = false;
bool expected_to_throw = false; DisallowReassignment<bool> expected_to_throw = {"throws", false};
bool ignore_unhandled_promises = false; DisallowReassignment<bool> ignore_unhandled_promises = {
bool mock_arraybuffer_allocator = false; "ignore-unhandled-promises", false};
size_t mock_arraybuffer_allocator_limit = 0; DisallowReassignment<bool> mock_arraybuffer_allocator = {
bool multi_mapped_mock_allocator = false; "mock-arraybuffer-allocator", false};
bool enable_inspector = false; DisallowReassignment<size_t> mock_arraybuffer_allocator_limit = {
"mock-arraybuffer-allocator-limit", 0};
DisallowReassignment<bool> multi_mapped_mock_allocator = {
"multi-mapped-mock-allocator", false};
DisallowReassignment<bool> enable_inspector = {"enable-inspector", false};
int num_isolates = 1; int num_isolates = 1;
v8::ScriptCompiler::CompileOptions compile_options = DisallowReassignment<v8::ScriptCompiler::CompileOptions, true>
v8::ScriptCompiler::kNoCompileOptions; compile_options = {"cache", v8::ScriptCompiler::kNoCompileOptions};
CodeCacheOptions code_cache_options = CodeCacheOptions::kNoProduceCache; DisallowReassignment<CodeCacheOptions, true> code_cache_options = {
bool streaming_compile = false; "cache", CodeCacheOptions::kNoProduceCache};
SourceGroup* isolate_sources = nullptr; DisallowReassignment<bool> streaming_compile = {"streaming-compile", false};
const char* icu_data_file = nullptr; DisallowReassignment<SourceGroup*> isolate_sources = {"isolate-sources",
const char* icu_locale = nullptr; nullptr};
const char* snapshot_blob = nullptr; DisallowReassignment<const char*> icu_data_file = {"icu-data-file", nullptr};
bool trace_enabled = false; DisallowReassignment<const char*> icu_locale = {"icu-locale", nullptr};
const char* trace_path = nullptr; DisallowReassignment<const char*> snapshot_blob = {"snapshot_blob", nullptr};
const char* trace_config = nullptr; DisallowReassignment<bool> trace_enabled = {"trace-enabled", false};
const char* lcov_file = nullptr; DisallowReassignment<const char*> trace_path = {"trace-path", nullptr};
bool disable_in_process_stack_traces = false; DisallowReassignment<const char*> trace_config = {"trace-config", nullptr};
int read_from_tcp_port = -1; DisallowReassignment<const char*> lcov_file = {"lcov", nullptr};
bool enable_os_system = false; DisallowReassignment<bool> disable_in_process_stack_traces = {
bool quiet_load = false; "disable-in-process-stack-traces", false};
int thread_pool_size = 0; DisallowReassignment<int> read_from_tcp_port = {"read-from-tcp-port", -1};
bool stress_delay_tasks = false; DisallowReassignment<bool> enable_os_system = {"enable-os-system", false};
DisallowReassignment<bool> quiet_load = {"quiet-load", false};
DisallowReassignment<int> thread_pool_size = {"thread-pool-size", 0};
DisallowReassignment<bool> stress_delay_tasks = {"stress-delay-tasks", false};
std::vector<const char*> arguments; std::vector<const char*> arguments;
bool include_arguments = true; DisallowReassignment<bool> include_arguments = {"arguments", true};
bool cpu_profiler = false; DisallowReassignment<bool> cpu_profiler = {"cpu-profiler", false};
bool cpu_profiler_print = false; DisallowReassignment<bool> cpu_profiler_print = {"cpu-profiler-print", false};
bool fuzzy_module_file_extensions = true; DisallowReassignment<bool> fuzzy_module_file_extensions = {
"fuzzy-module-file-extensions", true};
}; };
class Shell : public i::AllStatic { class Shell : public i::AllStatic {
......
...@@ -15,6 +15,11 @@ ...@@ -15,6 +15,11 @@
#define DEFINE_IMPLICATION(whenflag, thenflag) \ #define DEFINE_IMPLICATION(whenflag, thenflag) \
DEFINE_VALUE_IMPLICATION(whenflag, thenflag, true) DEFINE_VALUE_IMPLICATION(whenflag, thenflag, true)
// A weak implication will be overwritten by a normal implication or by an
// explicit flag.
#define DEFINE_WEAK_IMPLICATION(whenflag, thenflag) \
DEFINE_WEAK_VALUE_IMPLICATION(whenflag, thenflag, true)
#define DEFINE_NEG_IMPLICATION(whenflag, thenflag) \ #define DEFINE_NEG_IMPLICATION(whenflag, thenflag) \
DEFINE_VALUE_IMPLICATION(whenflag, thenflag, false) DEFINE_VALUE_IMPLICATION(whenflag, thenflag, false)
...@@ -59,14 +64,22 @@ ...@@ -59,14 +64,22 @@
// We produce the code to set flags when it is implied by another flag. // We produce the code to set flags when it is implied by another flag.
#elif defined(FLAG_MODE_DEFINE_IMPLICATIONS) #elif defined(FLAG_MODE_DEFINE_IMPLICATIONS)
#define DEFINE_VALUE_IMPLICATION(whenflag, thenflag, value) \ #define DEFINE_VALUE_IMPLICATION(whenflag, thenflag, value) \
if (FLAG_##whenflag) FLAG_##thenflag = value; changed |= TriggerImplication(FLAG_##whenflag, #whenflag, &FLAG_##thenflag, \
value, false);
// A weak implication will be overwritten by a normal implication or by an
// explicit flag.
#define DEFINE_WEAK_VALUE_IMPLICATION(whenflag, thenflag, value) \
changed |= TriggerImplication(FLAG_##whenflag, #whenflag, &FLAG_##thenflag, \
value, true);
#define DEFINE_GENERIC_IMPLICATION(whenflag, statement) \ #define DEFINE_GENERIC_IMPLICATION(whenflag, statement) \
if (FLAG_##whenflag) statement; if (FLAG_##whenflag) statement;
#define DEFINE_NEG_VALUE_IMPLICATION(whenflag, thenflag, value) \ #define DEFINE_NEG_VALUE_IMPLICATION(whenflag, thenflag, value) \
if (!FLAG_##whenflag) FLAG_##thenflag = value; changed |= TriggerImplication(!FLAG_##whenflag, #whenflag, &FLAG_##thenflag, \
value, false);
// We apply a generic macro to the flags. // We apply a generic macro to the flags.
#elif defined(FLAG_MODE_APPLY) #elif defined(FLAG_MODE_APPLY)
...@@ -94,6 +107,10 @@ ...@@ -94,6 +107,10 @@
#define DEFINE_VALUE_IMPLICATION(whenflag, thenflag, value) #define DEFINE_VALUE_IMPLICATION(whenflag, thenflag, value)
#endif #endif
#ifndef DEFINE_WEAK_VALUE_IMPLICATION
#define DEFINE_WEAK_VALUE_IMPLICATION(whenflag, thenflag, value)
#endif
#ifndef DEFINE_GENERIC_IMPLICATION #ifndef DEFINE_GENERIC_IMPLICATION
#define DEFINE_GENERIC_IMPLICATION(whenflag, statement) #define DEFINE_GENERIC_IMPLICATION(whenflag, statement)
#endif #endif
...@@ -203,6 +220,14 @@ struct MaybeBoolFlag { ...@@ -203,6 +220,14 @@ struct MaybeBoolFlag {
// //
#define FLAG FLAG_FULL #define FLAG FLAG_FULL
// ATTENTION: This is set to true by default in d8. But for API compatibility,
// it generally defaults to false.
DEFINE_BOOL(abort_on_contradictory_flags, false,
"Disallow flags or implications overriding each other.")
// This implication is also hard-coded into the flags processing to make sure it
// becomes active before we even process subsequent flags.
DEFINE_NEG_IMPLICATION(fuzzing, abort_on_contradictory_flags)
// Flags for language modes and experimental language features. // Flags for language modes and experimental language features.
DEFINE_BOOL(use_strict, false, "enforce strict mode") DEFINE_BOOL(use_strict, false, "enforce strict mode")
...@@ -377,7 +402,27 @@ DEFINE_BOOL(future, FUTURE_BOOL, ...@@ -377,7 +402,27 @@ DEFINE_BOOL(future, FUTURE_BOOL,
"Implies all staged features that we want to ship in the " "Implies all staged features that we want to ship in the "
"not-too-far future") "not-too-far future")
DEFINE_IMPLICATION(future, write_protect_code_memory) DEFINE_WEAK_IMPLICATION(future, write_protect_code_memory)
// Flags for jitless
DEFINE_BOOL(jitless, V8_LITE_BOOL,
"Disable runtime allocation of executable memory.")
// Jitless V8 has a few implications:
DEFINE_NEG_IMPLICATION(jitless, opt)
// Field representation tracking is only used by TurboFan.
DEFINE_NEG_IMPLICATION(jitless, track_field_types)
DEFINE_NEG_IMPLICATION(jitless, track_heap_object_fields)
// Regexps are interpreted.
DEFINE_IMPLICATION(jitless, regexp_interpret_all)
// asm.js validation is disabled since it triggers wasm code generation.
DEFINE_NEG_IMPLICATION(jitless, validate_asm)
// --jitless also implies --no-expose-wasm, see InitializeOncePerProcessImpl.
#ifndef V8_TARGET_ARCH_ARM
// Unsupported on arm. See https://crbug.com/v8/8713.
DEFINE_NEG_IMPLICATION(jitless, interpreted_frames_native_stack)
#endif
DEFINE_BOOL(assert_types, false, DEFINE_BOOL(assert_types, false,
"generate runtime type assertions to test the typer") "generate runtime type assertions to test the typer")
...@@ -430,26 +475,6 @@ DEFINE_BOOL_READONLY(string_slices, true, "use string slices") ...@@ -430,26 +475,6 @@ DEFINE_BOOL_READONLY(string_slices, true, "use string slices")
DEFINE_INT(interrupt_budget, 144 * KB, DEFINE_INT(interrupt_budget, 144 * KB,
"interrupt budget which should be used for the profiler counter") "interrupt budget which should be used for the profiler counter")
// Flags for jitless
DEFINE_BOOL(jitless, V8_LITE_BOOL,
"Disable runtime allocation of executable memory.")
// Jitless V8 has a few implications:
DEFINE_NEG_IMPLICATION(jitless, opt)
// Field representation tracking is only used by TurboFan.
DEFINE_NEG_IMPLICATION(jitless, track_field_types)
DEFINE_NEG_IMPLICATION(jitless, track_heap_object_fields)
// Regexps are interpreted.
DEFINE_IMPLICATION(jitless, regexp_interpret_all)
// asm.js validation is disabled since it triggers wasm code generation.
DEFINE_NEG_IMPLICATION(jitless, validate_asm)
// --jitless also implies --no-expose-wasm, see InitializeOncePerProcessImpl.
#ifndef V8_TARGET_ARCH_ARM
// Unsupported on arm. See https://crbug.com/v8/8713.
DEFINE_NEG_IMPLICATION(jitless, interpreted_frames_native_stack)
#endif
// Flags for inline caching and feedback vectors. // Flags for inline caching and feedback vectors.
DEFINE_BOOL(use_ic, true, "use inline caching") DEFINE_BOOL(use_ic, true, "use inline caching")
DEFINE_INT(budget_for_feedback_vector_allocation, 1 * KB, DEFINE_INT(budget_for_feedback_vector_allocation, 1 * KB,
...@@ -524,7 +549,7 @@ DEFINE_BOOL(concurrent_inlining, false, ...@@ -524,7 +549,7 @@ DEFINE_BOOL(concurrent_inlining, false,
"run optimizing compiler's inlining phase on a separate thread") "run optimizing compiler's inlining phase on a separate thread")
DEFINE_INT(max_serializer_nesting, 25, DEFINE_INT(max_serializer_nesting, 25,
"maximum levels for nesting child serializers") "maximum levels for nesting child serializers")
DEFINE_IMPLICATION(future, concurrent_inlining) DEFINE_WEAK_IMPLICATION(future, concurrent_inlining)
DEFINE_BOOL(trace_heap_broker_verbose, false, DEFINE_BOOL(trace_heap_broker_verbose, false,
"trace the heap broker verbosely (all reports)") "trace the heap broker verbosely (all reports)")
DEFINE_BOOL(trace_heap_broker_memory, false, DEFINE_BOOL(trace_heap_broker_memory, false,
...@@ -1854,9 +1879,11 @@ DEFINE_IMPLICATION(unbox_double_fields, track_double_fields) ...@@ -1854,9 +1879,11 @@ DEFINE_IMPLICATION(unbox_double_fields, track_double_fields)
#undef DEFINE_STRING #undef DEFINE_STRING
#undef DEFINE_FLOAT #undef DEFINE_FLOAT
#undef DEFINE_IMPLICATION #undef DEFINE_IMPLICATION
#undef DEFINE_WEAK_IMPLICATION
#undef DEFINE_NEG_IMPLICATION #undef DEFINE_NEG_IMPLICATION
#undef DEFINE_NEG_VALUE_IMPLICATION #undef DEFINE_NEG_VALUE_IMPLICATION
#undef DEFINE_VALUE_IMPLICATION #undef DEFINE_VALUE_IMPLICATION
#undef DEFINE_WEAK_VALUE_IMPLICATION
#undef DEFINE_GENERIC_IMPLICATION #undef DEFINE_GENERIC_IMPLICATION
#undef DEFINE_ALIAS_BOOL #undef DEFINE_ALIAS_BOOL
#undef DEFINE_ALIAS_INT #undef DEFINE_ALIAS_INT
......
...@@ -8,9 +8,11 @@ ...@@ -8,9 +8,11 @@
#include <cerrno> #include <cerrno>
#include <cinttypes> #include <cinttypes>
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include <sstream> #include <sstream>
#include "src/base/functional.h" #include "src/base/functional.h"
#include "src/base/logging.h"
#include "src/base/platform/platform.h" #include "src/base/platform/platform.h"
#include "src/codegen/cpu-features.h" #include "src/codegen/cpu-features.h"
#include "src/logging/counters.h" #include "src/logging/counters.h"
...@@ -33,6 +35,10 @@ namespace internal { ...@@ -33,6 +35,10 @@ namespace internal {
namespace { namespace {
struct Flag;
Flag* FindFlagByPointer(const void* ptr);
Flag* FindFlagByName(const char* name);
// This structure represents a single entry in the flag system, with a pointer // This structure represents a single entry in the flag system, with a pointer
// to the actual flag, default value, comment, etc. This is designed to be POD // to the actual flag, default value, comment, etc. This is designed to be POD
// initialized as to avoid requiring static constructors. // initialized as to avoid requiring static constructors.
...@@ -48,12 +54,16 @@ struct Flag { ...@@ -48,12 +54,16 @@ struct Flag {
TYPE_STRING, TYPE_STRING,
}; };
enum class SetBy { kDefault, kWeakImplication, kImplication, kCommandLine };
FlagType type_; // What type of flag, bool, int, or string. FlagType type_; // What type of flag, bool, int, or string.
const char* name_; // Name of the flag, ex "my_flag". const char* name_; // Name of the flag, ex "my_flag".
void* valptr_; // Pointer to the global flag variable. void* valptr_; // Pointer to the global flag variable.
const void* defptr_; // Pointer to the default value. const void* defptr_; // Pointer to the default value.
const char* cmt_; // A comment about the flags purpose. const char* cmt_; // A comment about the flags purpose.
bool owns_ptr_; // Does the flag own its string value? bool owns_ptr_; // Does the flag own its string value?
SetBy set_by_ = SetBy::kDefault;
const char* implied_by_ = nullptr;
FlagType type() const { return type_; } FlagType type() const { return type_; }
...@@ -61,39 +71,90 @@ struct Flag { ...@@ -61,39 +71,90 @@ struct Flag {
const char* comment() const { return cmt_; } const char* comment() const { return cmt_; }
bool* bool_variable() const { bool PointsTo(const void* ptr) const { return valptr_ == ptr; }
bool bool_variable() const {
DCHECK(type_ == TYPE_BOOL);
return *reinterpret_cast<bool*>(valptr_);
}
void set_bool_variable(bool value, SetBy set_by) {
DCHECK(type_ == TYPE_BOOL); DCHECK(type_ == TYPE_BOOL);
return reinterpret_cast<bool*>(valptr_); bool change_flag = *reinterpret_cast<bool*>(valptr_) != value;
change_flag = CheckFlagChange(set_by, change_flag);
if (change_flag) *reinterpret_cast<bool*>(valptr_) = value;
} }
MaybeBoolFlag* maybe_bool_variable() const { MaybeBoolFlag maybe_bool_variable() const {
DCHECK(type_ == TYPE_MAYBE_BOOL); DCHECK(type_ == TYPE_MAYBE_BOOL);
return reinterpret_cast<MaybeBoolFlag*>(valptr_); return *reinterpret_cast<MaybeBoolFlag*>(valptr_);
}
void set_maybe_bool_variable(MaybeBoolFlag value, SetBy set_by) {
DCHECK(type_ == TYPE_MAYBE_BOOL);
bool change_flag = *reinterpret_cast<MaybeBoolFlag*>(valptr_) != value;
change_flag = CheckFlagChange(set_by, change_flag);
if (change_flag) *reinterpret_cast<MaybeBoolFlag*>(valptr_) = value;
}
int int_variable() const {
DCHECK(type_ == TYPE_INT);
return *reinterpret_cast<int*>(valptr_);
} }
int* int_variable() const { void set_int_variable(int value, SetBy set_by) {
DCHECK(type_ == TYPE_INT); DCHECK(type_ == TYPE_INT);
return reinterpret_cast<int*>(valptr_); bool change_flag = *reinterpret_cast<int*>(valptr_) != value;
change_flag = CheckFlagChange(set_by, change_flag);
if (change_flag) *reinterpret_cast<int*>(valptr_) = value;
}
unsigned int uint_variable() const {
DCHECK(type_ == TYPE_UINT);
return *reinterpret_cast<unsigned int*>(valptr_);
} }
unsigned int* uint_variable() const { void set_uint_variable(unsigned int value, SetBy set_by) {
DCHECK(type_ == TYPE_UINT); DCHECK(type_ == TYPE_UINT);
return reinterpret_cast<unsigned int*>(valptr_); bool change_flag = *reinterpret_cast<unsigned int*>(valptr_) != value;
change_flag = CheckFlagChange(set_by, change_flag);
if (change_flag) *reinterpret_cast<unsigned int*>(valptr_) = value;
} }
uint64_t* uint64_variable() const { uint64_t uint64_variable() const {
DCHECK(type_ == TYPE_UINT64); DCHECK(type_ == TYPE_UINT64);
return reinterpret_cast<uint64_t*>(valptr_); return *reinterpret_cast<uint64_t*>(valptr_);
} }
double* float_variable() const { void set_uint64_variable(uint64_t value, SetBy set_by) {
DCHECK(type_ == TYPE_UINT64);
bool change_flag = *reinterpret_cast<uint64_t*>(valptr_) != value;
change_flag = CheckFlagChange(set_by, change_flag);
if (change_flag) *reinterpret_cast<uint64_t*>(valptr_) = value;
}
double float_variable() const {
DCHECK(type_ == TYPE_FLOAT); DCHECK(type_ == TYPE_FLOAT);
return reinterpret_cast<double*>(valptr_); return *reinterpret_cast<double*>(valptr_);
}
void set_float_variable(double value, SetBy set_by) {
DCHECK(type_ == TYPE_FLOAT);
bool change_flag = *reinterpret_cast<double*>(valptr_) != value;
change_flag = CheckFlagChange(set_by, change_flag);
if (change_flag) *reinterpret_cast<double*>(valptr_) = value;
}
size_t size_t_variable() const {
DCHECK(type_ == TYPE_SIZE_T);
return *reinterpret_cast<size_t*>(valptr_);
} }
size_t* size_t_variable() const { void set_size_t_variable(size_t value, SetBy set_by) {
DCHECK(type_ == TYPE_SIZE_T); DCHECK(type_ == TYPE_SIZE_T);
return reinterpret_cast<size_t*>(valptr_); bool change_flag = *reinterpret_cast<size_t*>(valptr_) != value;
change_flag = CheckFlagChange(set_by, change_flag);
if (change_flag) *reinterpret_cast<size_t*>(valptr_) = value;
} }
const char* string_value() const { const char* string_value() const {
...@@ -101,12 +162,19 @@ struct Flag { ...@@ -101,12 +162,19 @@ struct Flag {
return *reinterpret_cast<const char**>(valptr_); return *reinterpret_cast<const char**>(valptr_);
} }
void set_string_value(const char* value, bool owns_ptr) { void set_string_value(const char* value, bool owns_ptr, SetBy set_by) {
DCHECK(type_ == TYPE_STRING); DCHECK(type_ == TYPE_STRING);
const char** ptr = reinterpret_cast<const char**>(valptr_); const char** ptr = reinterpret_cast<const char**>(valptr_);
if (owns_ptr_ && *ptr != nullptr) DeleteArray(*ptr); bool change_flag = (*ptr == nullptr) != (value == nullptr) ||
*ptr = value; (*ptr && value && std::strcmp(*ptr, value) != 0);
owns_ptr_ = owns_ptr; change_flag = CheckFlagChange(set_by, change_flag);
if (change_flag) {
if (owns_ptr_ && *ptr != nullptr) DeleteArray(*ptr);
*ptr = value;
owns_ptr_ = owns_ptr;
} else {
if (owns_ptr && value != nullptr) DeleteArray(value);
}
} }
bool bool_default() const { bool bool_default() const {
...@@ -144,23 +212,95 @@ struct Flag { ...@@ -144,23 +212,95 @@ struct Flag {
return *reinterpret_cast<const char* const*>(defptr_); return *reinterpret_cast<const char* const*>(defptr_);
} }
static bool ShouldCheckFlagContradictions() {
return FLAG_abort_on_contradictory_flags && !FLAG_fuzzing;
}
// {change_flag} indicates if we're going to change the flag value.
// Returns an updated value for {change_flag}, which is changed to false if a
// weak implication is being ignored beause a flag is already set by a normal
// implication or from the command-line.
bool CheckFlagChange(SetBy new_set_by, bool change_flag,
const char* implied_by = nullptr) {
if (new_set_by == SetBy::kWeakImplication &&
(set_by_ == SetBy::kImplication || set_by_ == SetBy::kCommandLine)) {
return false;
}
if (ShouldCheckFlagContradictions()) {
// For bool flags, we only check for a conflict if the value actually
// changes. So specifying the same flag with the same value multiple times
// is allowed.
// For other flags, we disallow specifying them explicitly or in the
// presence of an implication even if the value is the same.
// This is to simplify the rules describing conflicts in variants.py: A
// repeated non-boolean flag is considered an error independently of its
// value.
bool is_bool_flag = type_ == TYPE_MAYBE_BOOL || type_ == TYPE_BOOL;
bool check_implications = change_flag;
bool check_command_line_flags = change_flag || !is_bool_flag;
const char* hint =
"To fix this, it might be necessary to specify additional "
"contradictory flags in tools/testrunner/local/variants.py.";
switch (set_by_) {
case SetBy::kDefault:
break;
case SetBy::kWeakImplication:
if (new_set_by == SetBy::kWeakImplication && check_implications) {
FATAL(
"Contradictory weak flag implications from --%s and --%s for "
"flag %s\n%s",
implied_by_, implied_by, name(), hint);
}
break;
case SetBy::kImplication:
if (new_set_by == SetBy::kImplication && check_implications) {
FATAL(
"Contradictory flag implications from --%s and --%s for flag "
"%s\n%s",
implied_by_, implied_by, name(), hint);
}
break;
case SetBy::kCommandLine:
if (new_set_by == SetBy::kImplication && check_command_line_flags) {
FATAL(
"Flag --%s is implied by --%s but also specified "
"explicitly.\n%s",
name(), implied_by, hint);
} else if (new_set_by == SetBy::kCommandLine &&
check_command_line_flags) {
FATAL(
"Command-line provided flag --%s specified multiple times.\n%s",
name(), hint);
}
break;
}
}
set_by_ = new_set_by;
if (new_set_by == SetBy::kImplication ||
new_set_by == SetBy::kWeakImplication) {
DCHECK_NOT_NULL(implied_by);
implied_by_ = implied_by;
}
return change_flag;
}
// Compare this flag's current value against the default. // Compare this flag's current value against the default.
bool IsDefault() const { bool IsDefault() const {
switch (type_) { switch (type_) {
case TYPE_BOOL: case TYPE_BOOL:
return *bool_variable() == bool_default(); return bool_variable() == bool_default();
case TYPE_MAYBE_BOOL: case TYPE_MAYBE_BOOL:
return maybe_bool_variable()->has_value == false; return maybe_bool_variable().has_value == false;
case TYPE_INT: case TYPE_INT:
return *int_variable() == int_default(); return int_variable() == int_default();
case TYPE_UINT: case TYPE_UINT:
return *uint_variable() == uint_default(); return uint_variable() == uint_default();
case TYPE_UINT64: case TYPE_UINT64:
return *uint64_variable() == uint64_default(); return uint64_variable() == uint64_default();
case TYPE_FLOAT: case TYPE_FLOAT:
return *float_variable() == float_default(); return float_variable() == float_default();
case TYPE_SIZE_T: case TYPE_SIZE_T:
return *size_t_variable() == size_t_default(); return size_t_variable() == size_t_default();
case TYPE_STRING: { case TYPE_STRING: {
const char* str1 = string_value(); const char* str1 = string_value();
const char* str2 = string_default(); const char* str2 = string_default();
...@@ -176,31 +316,34 @@ struct Flag { ...@@ -176,31 +316,34 @@ struct Flag {
void Reset() { void Reset() {
switch (type_) { switch (type_) {
case TYPE_BOOL: case TYPE_BOOL:
*bool_variable() = bool_default(); set_bool_variable(bool_default(), SetBy::kDefault);
break; break;
case TYPE_MAYBE_BOOL: case TYPE_MAYBE_BOOL:
*maybe_bool_variable() = MaybeBoolFlag::Create(false, false); set_maybe_bool_variable(MaybeBoolFlag::Create(false, false),
SetBy::kDefault);
break; break;
case TYPE_INT: case TYPE_INT:
*int_variable() = int_default(); set_int_variable(int_default(), SetBy::kDefault);
break; break;
case TYPE_UINT: case TYPE_UINT:
*uint_variable() = uint_default(); set_uint_variable(uint_default(), SetBy::kDefault);
break; break;
case TYPE_UINT64: case TYPE_UINT64:
*uint64_variable() = uint64_default(); set_uint64_variable(uint64_default(), SetBy::kDefault);
break; break;
case TYPE_FLOAT: case TYPE_FLOAT:
*float_variable() = float_default(); set_float_variable(float_default(), SetBy::kDefault);
break; break;
case TYPE_SIZE_T: case TYPE_SIZE_T:
*size_t_variable() = size_t_default(); set_size_t_variable(size_t_default(), SetBy::kDefault);
break; break;
case TYPE_STRING: case TYPE_STRING:
set_string_value(string_default(), false); set_string_value(string_default(), false, SetBy::kDefault);
break; break;
} }
} }
void AllowOverwriting() { set_by_ = SetBy::kDefault; }
}; };
Flag flags[] = { Flag flags[] = {
...@@ -210,6 +353,31 @@ Flag flags[] = { ...@@ -210,6 +353,31 @@ Flag flags[] = {
const size_t num_flags = sizeof(flags) / sizeof(*flags); const size_t num_flags = sizeof(flags) / sizeof(*flags);
inline char NormalizeChar(char ch) { return ch == '_' ? '-' : ch; }
bool EqualNames(const char* a, const char* b) {
for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
if (a[i] == '\0') {
return true;
}
}
return false;
}
Flag* FindFlagByName(const char* name) {
for (size_t i = 0; i < num_flags; ++i) {
if (EqualNames(name, flags[i].name())) return &flags[i];
}
return nullptr;
}
Flag* FindFlagByPointer(const void* ptr) {
for (size_t i = 0; i < num_flags; ++i) {
if (flags[i].PointsTo(ptr)) return &flags[i];
}
return nullptr;
}
} // namespace } // namespace
static const char* Type2String(Flag::FlagType type) { static const char* Type2String(Flag::FlagType type) {
...@@ -237,27 +405,27 @@ static const char* Type2String(Flag::FlagType type) { ...@@ -237,27 +405,27 @@ static const char* Type2String(Flag::FlagType type) {
std::ostream& operator<<(std::ostream& os, const Flag& flag) { // NOLINT std::ostream& operator<<(std::ostream& os, const Flag& flag) { // NOLINT
switch (flag.type()) { switch (flag.type()) {
case Flag::TYPE_BOOL: case Flag::TYPE_BOOL:
os << (*flag.bool_variable() ? "true" : "false"); os << (flag.bool_variable() ? "true" : "false");
break; break;
case Flag::TYPE_MAYBE_BOOL: case Flag::TYPE_MAYBE_BOOL:
os << (flag.maybe_bool_variable()->has_value os << (flag.maybe_bool_variable().has_value
? (flag.maybe_bool_variable()->value ? "true" : "false") ? (flag.maybe_bool_variable().value ? "true" : "false")
: "unset"); : "unset");
break; break;
case Flag::TYPE_INT: case Flag::TYPE_INT:
os << *flag.int_variable(); os << flag.int_variable();
break; break;
case Flag::TYPE_UINT: case Flag::TYPE_UINT:
os << *flag.uint_variable(); os << flag.uint_variable();
break; break;
case Flag::TYPE_UINT64: case Flag::TYPE_UINT64:
os << *flag.uint64_variable(); os << flag.uint64_variable();
break; break;
case Flag::TYPE_FLOAT: case Flag::TYPE_FLOAT:
os << *flag.float_variable(); os << flag.float_variable();
break; break;
case Flag::TYPE_SIZE_T: case Flag::TYPE_SIZE_T:
os << *flag.size_t_variable(); os << flag.size_t_variable();
break; break;
case Flag::TYPE_STRING: { case Flag::TYPE_STRING: {
const char* str = flag.string_value(); const char* str = flag.string_value();
...@@ -275,7 +443,7 @@ std::vector<const char*>* FlagList::argv() { ...@@ -275,7 +443,7 @@ std::vector<const char*>* FlagList::argv() {
Flag* f = &flags[i]; Flag* f = &flags[i];
if (!f->IsDefault()) { if (!f->IsDefault()) {
{ {
bool disabled = f->type() == Flag::TYPE_BOOL && !*f->bool_variable(); bool disabled = f->type() == Flag::TYPE_BOOL && !f->bool_variable();
std::ostringstream os; std::ostringstream os;
os << (disabled ? "--no" : "--") << f->name(); os << (disabled ? "--no" : "--") << f->name();
args->push_back(StrDup(os.str().c_str())); args->push_back(StrDup(os.str().c_str()));
...@@ -290,8 +458,6 @@ std::vector<const char*>* FlagList::argv() { ...@@ -290,8 +458,6 @@ std::vector<const char*>* FlagList::argv() {
return args; return args;
} }
inline char NormalizeChar(char ch) { return ch == '_' ? '-' : ch; }
// Helper function to parse flags: Takes an argument arg and splits it into // Helper function to parse flags: Takes an argument arg and splits it into
// a flag name and flag value (or nullptr if they are missing). negated is set // a flag name and flag value (or nullptr if they are missing). negated is set
// if the arg started with "-no" or "--no". The buffer may be used to NUL- // if the arg started with "-no" or "--no". The buffer may be used to NUL-
...@@ -334,22 +500,6 @@ static void SplitArgument(const char* arg, char* buffer, int buffer_size, ...@@ -334,22 +500,6 @@ static void SplitArgument(const char* arg, char* buffer, int buffer_size,
} }
} }
static bool EqualNames(const char* a, const char* b) {
for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
if (a[i] == '\0') {
return true;
}
}
return false;
}
static Flag* FindFlag(const char* name) {
for (size_t i = 0; i < num_flags; ++i) {
if (EqualNames(name, flags[i].name())) return &flags[i];
}
return nullptr;
}
template <typename T> template <typename T>
bool TryParseUnsigned(Flag* flag, const char* arg, const char* value, bool TryParseUnsigned(Flag* flag, const char* arg, const char* value,
char** endp, T* out_val) { char** endp, T* out_val) {
...@@ -388,7 +538,7 @@ int FlagList::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags, ...@@ -388,7 +538,7 @@ int FlagList::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags,
if (name != nullptr) { if (name != nullptr) {
// lookup the flag // lookup the flag
Flag* flag = FindFlag(name); Flag* flag = FindFlagByName(name);
if (flag == nullptr) { if (flag == nullptr) {
if (remove_flags) { if (remove_flags) {
// We don't recognize this flag but since we're removing // We don't recognize this flag but since we're removing
...@@ -421,37 +571,50 @@ int FlagList::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags, ...@@ -421,37 +571,50 @@ int FlagList::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags,
char* endp = const_cast<char*>(""); // *endp is only read char* endp = const_cast<char*>(""); // *endp is only read
switch (flag->type()) { switch (flag->type()) {
case Flag::TYPE_BOOL: case Flag::TYPE_BOOL:
*flag->bool_variable() = !negated; flag->set_bool_variable(!negated, Flag::SetBy::kCommandLine);
break; break;
case Flag::TYPE_MAYBE_BOOL: case Flag::TYPE_MAYBE_BOOL:
*flag->maybe_bool_variable() = MaybeBoolFlag::Create(true, !negated); flag->set_maybe_bool_variable(MaybeBoolFlag::Create(true, !negated),
Flag::SetBy::kCommandLine);
break; break;
case Flag::TYPE_INT: case Flag::TYPE_INT:
*flag->int_variable() = static_cast<int>(strtol(value, &endp, 10)); flag->set_int_variable(static_cast<int>(strtol(value, &endp, 10)),
Flag::SetBy::kCommandLine);
break; break;
case Flag::TYPE_UINT: case Flag::TYPE_UINT: {
if (!TryParseUnsigned(flag, arg, value, &endp, unsigned int parsed_value;
flag->uint_variable())) { if (TryParseUnsigned(flag, arg, value, &endp, &parsed_value)) {
flag->set_uint_variable(parsed_value, Flag::SetBy::kCommandLine);
} else {
return_code = j; return_code = j;
} }
break; break;
case Flag::TYPE_UINT64: }
if (!TryParseUnsigned(flag, arg, value, &endp, case Flag::TYPE_UINT64: {
flag->uint64_variable())) { uint64_t parsed_value;
if (TryParseUnsigned(flag, arg, value, &endp, &parsed_value)) {
flag->set_uint64_variable(parsed_value, Flag::SetBy::kCommandLine);
} else {
return_code = j; return_code = j;
} }
break; break;
}
case Flag::TYPE_FLOAT: case Flag::TYPE_FLOAT:
*flag->float_variable() = strtod(value, &endp); flag->set_float_variable(strtod(value, &endp),
Flag::SetBy::kCommandLine);
break; break;
case Flag::TYPE_SIZE_T: case Flag::TYPE_SIZE_T: {
if (!TryParseUnsigned(flag, arg, value, &endp, size_t parsed_value;
flag->size_t_variable())) { if (TryParseUnsigned(flag, arg, value, &endp, &parsed_value)) {
flag->set_size_t_variable(parsed_value, Flag::SetBy::kCommandLine);
} else {
return_code = j; return_code = j;
} }
break; break;
}
case Flag::TYPE_STRING: case Flag::TYPE_STRING:
flag->set_string_value(value ? StrDup(value) : nullptr, true); flag->set_string_value(value ? StrDup(value) : nullptr, true,
Flag::SetBy::kCommandLine);
break; break;
} }
...@@ -588,6 +751,8 @@ void FlagList::PrintHelp() { ...@@ -588,6 +751,8 @@ void FlagList::PrintHelp() {
} }
} }
namespace {
static uint32_t flag_hash = 0; static uint32_t flag_hash = 0;
void ComputeFlagListHash() { void ComputeFlagListHash() {
...@@ -600,8 +765,7 @@ void ComputeFlagListHash() { ...@@ -600,8 +765,7 @@ void ComputeFlagListHash() {
} }
for (size_t i = 0; i < num_flags; ++i) { for (size_t i = 0; i < num_flags; ++i) {
Flag* current = &flags[i]; Flag* current = &flags[i];
if (current->type() == Flag::TYPE_BOOL && if (current->PointsTo(&FLAG_profile_deserialization)) {
current->bool_variable() == &FLAG_profile_deserialization) {
// We want to be able to flip --profile-deserialization without // We want to be able to flip --profile-deserialization without
// causing the code cache to get invalidated by this hash. // causing the code cache to get invalidated by this hash.
continue; continue;
...@@ -616,11 +780,31 @@ void ComputeFlagListHash() { ...@@ -616,11 +780,31 @@ void ComputeFlagListHash() {
base::hash_range(args.c_str(), args.c_str() + args.length())); base::hash_range(args.c_str(), args.c_str() + args.length()));
} }
template <class A, class B>
bool TriggerImplication(bool premise, const char* premise_name,
A* conclusion_pointer, B value, bool weak_implication) {
if (!premise) return false;
bool change_flag = *conclusion_pointer != implicit_cast<A>(value);
Flag* conclusion_flag = FindFlagByPointer(conclusion_pointer);
change_flag = conclusion_flag->CheckFlagChange(
weak_implication ? Flag::SetBy::kWeakImplication
: Flag::SetBy::kImplication,
change_flag, premise_name);
if (change_flag) *conclusion_pointer = value;
return change_flag;
}
} // namespace
// static // static
void FlagList::EnforceFlagImplications() { void FlagList::EnforceFlagImplications() {
bool changed;
do {
changed = false;
#define FLAG_MODE_DEFINE_IMPLICATIONS #define FLAG_MODE_DEFINE_IMPLICATIONS
#include "src/flags/flag-definitions.h" // NOLINT(build/include) #include "src/flags/flag-definitions.h" // NOLINT(build/include)
#undef FLAG_MODE_DEFINE_IMPLICATIONS #undef FLAG_MODE_DEFINE_IMPLICATIONS
} while (changed);
ComputeFlagListHash(); ComputeFlagListHash();
} }
......
...@@ -1057,6 +1057,7 @@ int main(int argc, char* argv[]) { ...@@ -1057,6 +1057,7 @@ int main(int argc, char* argv[]) {
v8::V8::InitializeICUDefaultLocation(argv[0]); v8::V8::InitializeICUDefaultLocation(argv[0]);
std::unique_ptr<v8::Platform> platform(v8::platform::NewDefaultPlatform()); std::unique_ptr<v8::Platform> platform(v8::platform::NewDefaultPlatform());
v8::V8::InitializePlatform(platform.get()); v8::V8::InitializePlatform(platform.get());
v8::internal::FLAG_abort_on_contradictory_flags = true;
v8::V8::SetFlagsFromCommandLine(&argc, argv, true); v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
v8::V8::InitializeExternalStartupData(argv[0]); v8::V8::InitializeExternalStartupData(argv[0]);
v8::V8::Initialize(); v8::V8::Initialize();
......
...@@ -91,6 +91,11 @@ ...@@ -91,6 +91,11 @@
'*': [SKIP], # only relevant for mjsunit tests. '*': [SKIP], # only relevant for mjsunit tests.
}], }],
################################################################################
['variant == stress', {
'*': [SKIP], # only relevant for mjsunit tests.
}],
############################################################################## ##############################################################################
['tsan == True', { ['tsan == True', {
# TSan handles SIGPROF incorrectly (https://crbug.com/v8/9869). # TSan handles SIGPROF incorrectly (https://crbug.com/v8/9869).
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --no-stress-opt --trace-wasm-memory --liftoff --no-future // Flags: --no-stress-opt --trace-wasm-memory --liftoff
// Flags: --no-wasm-tier-up --experimental-wasm-simd // Flags: --no-wasm-tier-up --experimental-wasm-simd
// Flags: --enable-sse3 --enable-sse4-1 // Flags: --enable-sse3 --enable-sse4-1
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --no-stress-opt --trace-wasm-memory --no-liftoff --no-future // Flags: --no-stress-opt --trace-wasm-memory --no-liftoff
// Flags: --experimental-wasm-simd // Flags: --experimental-wasm-simd
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
......
...@@ -2,8 +2,15 @@ ...@@ -2,8 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --allow-natives-syntax --noverify-heap --noenable-slow-asserts // The flags are processed left to right. --no-abort-on-contradictory-flags
// Flags: --opt --no-always-opt // disables the checking for conflicts, then we process --noverify-heap and
// --noenable-slow-asserts, which the test runner already set to true before.
// This causes the flags to be overwritten while silencing the error. Then we
// re-enable --abort-on-contradictory-flags to make sure that the processing of
// other flags and flag implications, which happens later, still produces
// errors.
// Flags: --no-abort-on-contradictory-flags --noverify-heap --noenable-slow-asserts --abort-on-contradictory-flags
// Flags: --allow-natives-syntax --opt --no-always-opt
// --noverify-heap and --noenable-slow-asserts are set because the test is too // --noverify-heap and --noenable-slow-asserts are set because the test is too
// slow with it on. // slow with it on.
......
...@@ -376,17 +376,6 @@ ...@@ -376,17 +376,6 @@
'regexp-tier-up-multiple': [SKIP], 'regexp-tier-up-multiple': [SKIP],
'regress/regress-996234': [SKIP], 'regress/regress-996234': [SKIP],
# Tests that depend on optimization (beyond doing assertOptimized).
'compiler/is-being-interpreted-*': [SKIP],
'compiler/serializer-accessors': [SKIP],
'compiler/serializer-apply': [SKIP],
'compiler/serializer-call': [SKIP],
'compiler/serializer-dead-after-jump': [SKIP],
'compiler/serializer-dead-after-return': [SKIP],
'compiler/serializer-transition-propagation': [SKIP],
'regress/regress-1049982-1': [SKIP],
'regress/regress-1049982-2': [SKIP],
# These tests check that we can trace the compiler. # These tests check that we can trace the compiler.
'tools/compiler-trace-flags': [SKIP], 'tools/compiler-trace-flags': [SKIP],
'tools/compiler-trace-flags-wasm': [SKIP], 'tools/compiler-trace-flags-wasm': [SKIP],
...@@ -1177,10 +1166,6 @@ ...@@ -1177,10 +1166,6 @@
'regress/regress-1049982-2': [SKIP], 'regress/regress-1049982-2': [SKIP],
'es6/iterator-eager-deopt': [SKIP], 'es6/iterator-eager-deopt': [SKIP],
# interrupt_budget overrides don't work with TurboProp.
'interrupt-budget-override': [SKIP],
'never-optimize': [SKIP],
# In turboprop we reuse the optimized code on soft deopt. The following tests # In turboprop we reuse the optimized code on soft deopt. The following tests
# test for a soft deopt and they won't work in TurboProp. # test for a soft deopt and they won't work in TurboProp.
'deopt-recursive-soft-once': [SKIP], 'deopt-recursive-soft-once': [SKIP],
......
...@@ -2,7 +2,15 @@ ...@@ -2,7 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --random-seed=20 --nostress-opt --noalways-opt --predictable // Overwrite the random seed provided by the test runner to make this test less
// flaky.
// The flags are processed left to right. --no-abort-on-contradictory-flags
// disables the checking for conflicts, then we process --random-seed=20 to
// overwrite the value the test runner already set before. Then we re-enable
// --abort-on-contradictory-flags to make sure that the processing of other
// flags and flag implications, which happens later, still produces errors.
// Flags: --no-abort-on-contradictory-flags --random-seed=20 --abort-on-contradictory-flags
// Flags: --nostress-opt --noalways-opt --predictable
(function() { (function() {
var kHistory = 2; var kHistory = 2;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --noconcurrent-recompilation --expose-gc --allow-natives-syntax // Flags: --expose-gc --allow-natives-syntax
// Flags: --concurrent-recompilation --block-concurrent-recompilation // Flags: --concurrent-recompilation --block-concurrent-recompilation
gc(); gc();
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --allow-natives-syntax --gc-interval=439 --random-seed=-423594851 // Flags: --allow-natives-syntax --gc-interval=439
var __v_3; var __v_3;
function __f_2() { function __f_2() {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// Flags: --allow-natives-syntax --stress-compaction // Flags: --allow-natives-syntax --stress-compaction
// To reliably reproduce the crash use --verify-heap --random-seed=-133185440 // To reliably reproduce the crash use --verify-heap
function __f_2(o) { function __f_2(o) {
return o.field.b.x; return o.field.b.x;
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --random-seed=1
for (let i = 0; i < 54; ++i) Math.random(); for (let i = 0; i < 54; ++i) Math.random();
let sum = 0; let sum = 0;
for (let i = 0; i < 10; ++i) for (let i = 0; i < 10; ++i)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --no-liftoff --no-future --debug-code // Flags: --no-liftoff --debug-code
load('test/mjsunit/wasm/wasm-module-builder.js'); load('test/mjsunit/wasm/wasm-module-builder.js');
......
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --random-seed=-1595876594 --disable-in-process-stack-traces --no-lazy // Flags: --disable-in-process-stack-traces --no-lazy
var __v_47 = ({[__v_46]: __f_52}) => { var __v_46 = 'b'; return __f_52; }; var __v_47 = ({[__v_46]: __f_52}) => { var __v_46 = 'b'; return __f_52; };
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --expose-gc --predictable --random-seed=-1109634722 // Flags: --expose-gc --predictable
gc(); gc();
gc(); gc();
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// Flags: --random-seed=891196975 --expose-gc --allow-natives-syntax // Flags: --expose-gc --allow-natives-syntax
// Flags: --gc-interval=207 --stress-compaction --validate-asm // Flags: --gc-interval=207 --stress-compaction --validate-asm
// Flags: --opt --no-always-opt // Flags: --opt --no-always-opt
// //
......
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// Flags: --random-seed=891196975 --expose-gc --allow-natives-syntax // Flags: --expose-gc --allow-natives-syntax --gc-interval=207
// Flags: --gc-interval=207 --stress-compaction --validate-asm // Flags: --stress-compaction --validate-asm --opt --no-always-opt
// Flags: --opt --no-always-opt
// //
// /v8/test/mjsunit/wasm/grow-memory.js // /v8/test/mjsunit/wasm/grow-memory.js
// /v8/test/mjsunit/regress/regress-540.js // /v8/test/mjsunit/regress/regress-540.js
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --random-seed=1557792826 --expose-gc --invoke-weak-callbacks --omit-quit --gc-interval=469 --validate-asm // Flags: --expose-gc --invoke-weak-callbacks --omit-quit --gc-interval=469 --validate-asm
function nop() {} function nop() {}
var __v_42 = {}; var __v_42 = {};
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// Flags: --random-seed=-1101427159 --enable-slow-asserts --expose-wasm // Flags: --enable-slow-asserts --expose-wasm
(function __f_7() { (function __f_7() {
assertThrows(() => new WebAssembly.Memory({initial: 79199}), RangeError); assertThrows(() => new WebAssembly.Memory({initial: 79199}), RangeError);
......
...@@ -25,8 +25,7 @@ ...@@ -25,8 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --random-seed=17 --allow-natives-syntax // Flags: --allow-natives-syntax --expose-externalize-string
// Flags: --expose-externalize-string
assertEquals("ΚΟΣΜΟΣ ΚΟΣΜΟΣ".toLowerCase(), "κοσμος κοσμος"); assertEquals("ΚΟΣΜΟΣ ΚΟΣΜΟΣ".toLowerCase(), "κοσμος κοσμος");
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --allow-natives-syntax --liftoff --no-future --no-wasm-tier-up // Flags: --allow-natives-syntax --liftoff --no-wasm-tier-up
// Compile functions 0 and 2 with Turbofan, the rest with Liftoff: // Compile functions 0 and 2 with Turbofan, the rest with Liftoff:
// Flags: --wasm-tier-mask-for-testing=5 // Flags: --wasm-tier-mask-for-testing=5
......
...@@ -76,6 +76,7 @@ class StatusFile(object): ...@@ -76,6 +76,7 @@ class StatusFile(object):
_rules: {variant: {test name: [rule]}} _rules: {variant: {test name: [rule]}}
_prefix_rules: {variant: {test name prefix: [rule]}} _prefix_rules: {variant: {test name prefix: [rule]}}
""" """
self.variables = variables
with open(path) as f: with open(path) as f:
self._rules, self._prefix_rules = ReadStatusFile(f.read(), variables) self._rules, self._prefix_rules = ReadStatusFile(f.read(), variables)
......
...@@ -25,8 +25,7 @@ ALL_VARIANT_FLAGS = { ...@@ -25,8 +25,7 @@ ALL_VARIANT_FLAGS = {
# independent of JS optimizations, so we can combine those configs. # independent of JS optimizations, so we can combine those configs.
"nooptimization": [["--no-opt", "--liftoff", "--no-wasm-tier-up"]], "nooptimization": [["--no-opt", "--liftoff", "--no-wasm-tier-up"]],
"slow_path": [["--force-slow-path"]], "slow_path": [["--force-slow-path"]],
"stress": [["--stress-opt", "--always-opt", "--no-liftoff", "stress": [["--stress-opt", "--no-liftoff", "--stress-lazy-source-positions"]],
"--stress-lazy-source-positions"]],
"stress_js_bg_compile_wasm_code_gc": [["--stress-background-compile", "stress_js_bg_compile_wasm_code_gc": [["--stress-background-compile",
"--stress-wasm-code-gc"]], "--stress-wasm-code-gc"]],
"stress_incremental_marking": [["--stress-incremental-marking"]], "stress_incremental_marking": [["--stress-incremental-marking"]],
...@@ -41,6 +40,51 @@ ALL_VARIANT_FLAGS = { ...@@ -41,6 +40,51 @@ ALL_VARIANT_FLAGS = {
"top_level_await": [["--harmony-top-level-await"]], "top_level_await": [["--harmony-top-level-await"]],
} }
# Flags that lead to a contradiction with the flags provided by the respective
# variant. This depends on the flags specified in ALL_VARIANT_FLAGS and on the
# implications defined in flag-definitions.h.
INCOMPATIBLE_FLAGS_PER_VARIANT = {
"assert_types": ["--no-assert-types"],
"jitless": ["--opt", "--liftoff", "--track-field-types", "--validate-asm"],
"no_wasm_traps": ["--wasm-trap-handler"],
"nooptimization": ["--opt", "--no-liftoff", "--predictable", "--wasm-tier-up"],
"slow_path": ["--no-force-slow-path"],
"stress_incremental_marking": ["--no-stress-incremental-marking"],
"stress_js_bg_compile_wasm_code_gc": ["--no-stress-background-compile"],
"stress": ["--no-stress-opt", "--always-opt", "--no-always-opt", "--liftoff", "--max-inlined-bytecode-size=*",
"--max-inlined-bytecode-size-cumulative=*", "--stress-inline"],
"turboprop": ["--turbo-inlining", "--interrupt-budget=*", "--no-turboprop"],
}
# Flags that lead to a contradiction under certain build variables.
# This corresponds to the build variables usable in status files as generated
# in _get_statusfile_variables in base_runner.py.
# The conflicts might be directly contradictory flags or be caused by the
# implications defined in flag-definitions.h.
INCOMPATIBLE_FLAGS_PER_BUILD_VARIABLE = {
"lite_mode": ["--no-lazy-feedback-allocation", "--max-semi-space-size=*"]
+ INCOMPATIBLE_FLAGS_PER_VARIANT["jitless"],
"predictable": ["--liftoff", "--parallel-compile-tasks",
"--concurrent-recompilation",
"--wasm-num-compilation-tasks=*"],
}
# Flags that lead to a contradiction when a certain extra-flag is present.
# Such extra-flags are defined for example in infra/testing/builders.pyl or in
# standard_runner.py.
# The conflicts might be directly contradictory flags or be caused by the
# implications defined in flag-definitions.h.
INCOMPATIBLE_FLAGS_PER_EXTRA_FLAG = {
"--concurrent-recompilation": ["--no-concurrent-recompilation", "--predictable"],
"--enable-armv8": ["--no-enable-armv8"],
"--gc-interval=*": ["--gc-interval=*"],
"--no-enable-sse3": ["--enable-sse3"],
"--no-enable-sse4-1": ["--enable-sse4-1"],
"--optimize-for-size": ["--max-semi-space-size=*"],
"--stress-flush-bytecode": ["--no-stress-flush-bytecode"],
"--stress-incremental-marking": INCOMPATIBLE_FLAGS_PER_VARIANT["stress_incremental_marking"],
}
SLOW_VARIANTS = set([ SLOW_VARIANTS = set([
'stress', 'stress',
'stress_snapshot', 'stress_snapshot',
......
...@@ -34,6 +34,10 @@ from ..outproc import base as outproc ...@@ -34,6 +34,10 @@ from ..outproc import base as outproc
from ..local import command from ..local import command
from ..local import statusfile from ..local import statusfile
from ..local import utils from ..local import utils
from ..local.variants import INCOMPATIBLE_FLAGS_PER_VARIANT
from ..local.variants import INCOMPATIBLE_FLAGS_PER_BUILD_VARIABLE
from ..local.variants import INCOMPATIBLE_FLAGS_PER_EXTRA_FLAG
FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)") FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
...@@ -84,7 +88,8 @@ class TestCase(object): ...@@ -84,7 +88,8 @@ class TestCase(object):
# Outcomes # Outcomes
self._statusfile_outcomes = None self._statusfile_outcomes = None
self.expected_outcomes = None self._expected_outcomes = None
self._checked_flag_contradictions = False
self._statusfile_flags = None self._statusfile_flags = None
self._prepare_outcomes() self._prepare_outcomes()
...@@ -116,7 +121,7 @@ class TestCase(object): ...@@ -116,7 +121,7 @@ class TestCase(object):
outcomes = self.suite.statusfile.get_outcomes(self.name, self.variant) outcomes = self.suite.statusfile.get_outcomes(self.name, self.variant)
self._statusfile_outcomes = filter(not_flag, outcomes) self._statusfile_outcomes = filter(not_flag, outcomes)
self._statusfile_flags = filter(is_flag, outcomes) self._statusfile_flags = filter(is_flag, outcomes)
self.expected_outcomes = ( self._expected_outcomes = (
self._parse_status_file_outcomes(self._statusfile_outcomes)) self._parse_status_file_outcomes(self._statusfile_outcomes))
def _parse_status_file_outcomes(self, outcomes): def _parse_status_file_outcomes(self, outcomes):
...@@ -141,6 +146,45 @@ class TestCase(object): ...@@ -141,6 +146,45 @@ class TestCase(object):
return outproc.OUTCOMES_FAIL return outproc.OUTCOMES_FAIL
return expected_outcomes or outproc.OUTCOMES_PASS return expected_outcomes or outproc.OUTCOMES_PASS
@property
def expected_outcomes(self):
def normalize_flag(flag):
return flag.replace("_", "-").replace("--no-", "--no")
def has_flag(conflicting_flag, flags):
conflicting_flag = normalize_flag(conflicting_flag)
if conflicting_flag in flags:
return True
if conflicting_flag.endswith("*"):
return any(flag.startswith(conflicting_flag[:-1]) for flag in flags)
return False
if not self._checked_flag_contradictions:
self._checked_flag_contradictions = True
file_specific_flags = (self._get_source_flags() + self._get_suite_flags()
+ self._get_statusfile_flags())
file_specific_flags = [normalize_flag(flag) for flag in file_specific_flags]
extra_flags = [normalize_flag(flag) for flag in self._get_extra_flags()]
incompatible_flags = []
if self.variant in INCOMPATIBLE_FLAGS_PER_VARIANT:
incompatible_flags += INCOMPATIBLE_FLAGS_PER_VARIANT[self.variant]
for variable, flags in INCOMPATIBLE_FLAGS_PER_BUILD_VARIABLE.items():
if self.suite.statusfile.variables[variable]:
incompatible_flags += flags
for extra_flag, flags in INCOMPATIBLE_FLAGS_PER_EXTRA_FLAG.items():
if has_flag(extra_flag, extra_flags):
incompatible_flags += flags
for incompatible_flag in incompatible_flags:
if has_flag(incompatible_flag, file_specific_flags):
self._expected_outcomes = outproc.OUTCOMES_FAIL
return self._expected_outcomes
@property @property
def do_skip(self): def do_skip(self):
return (statusfile.SKIP in self._statusfile_outcomes and return (statusfile.SKIP in self._statusfile_outcomes and
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment