diff options
Diffstat (limited to 'chromium/v8/src/d8/d8.cc')
-rw-r--r-- | chromium/v8/src/d8/d8.cc | 579 |
1 files changed, 465 insertions, 114 deletions
diff --git a/chromium/v8/src/d8/d8.cc b/chromium/v8/src/d8/d8.cc index fe1bb58e4a9..117df1cc526 100644 --- a/chromium/v8/src/d8/d8.cc +++ b/chromium/v8/src/d8/d8.cc @@ -12,6 +12,7 @@ #include <iomanip> #include <iterator> #include <string> +#include <tuple> #include <unordered_map> #include <utility> #include <vector> @@ -35,7 +36,6 @@ #include "src/d8/d8.h" #include "src/debug/debug-interface.h" #include "src/deoptimizer/deoptimizer.h" -#include "src/diagnostics/basic-block-profiler.h" #include "src/execution/vm-state-inl.h" #include "src/handles/maybe-handles.h" #include "src/init/v8.h" @@ -55,6 +55,10 @@ #include "src/utils/utils.h" #include "src/wasm/wasm-engine.h" +#ifdef V8_FUZZILLI +#include "src/d8/cov.h" +#endif // V8_FUZZILLI + #ifdef V8_USE_PERFETTO #include "perfetto/tracing.h" #endif // V8_USE_PERFETTO @@ -92,6 +96,19 @@ namespace { const int kMB = 1024 * 1024; +#ifdef V8_FUZZILLI +// REPRL = read-eval-print-loop +// These file descriptors are being opened when Fuzzilli uses fork & execve to +// run V8. +#define REPRL_CRFD 100 // Control read file decriptor +#define REPRL_CWFD 101 // Control write file decriptor +#define REPRL_DRFD 102 // Data read file decriptor +#define REPRL_DWFD 103 // Data write file decriptor +bool fuzzilli_reprl = true; +#else +bool fuzzilli_reprl = false; +#endif // V8_FUZZILLI + const int kMaxSerializerMemoryUsage = 1 * kMB; // Arbitrary maximum for testing. @@ -417,7 +434,7 @@ static platform::tracing::TraceConfig* CreateTraceConfigFromJSON( class ExternalOwningOneByteStringResource : public String::ExternalOneByteStringResource { public: - ExternalOwningOneByteStringResource() {} + ExternalOwningOneByteStringResource() = default; ExternalOwningOneByteStringResource( std::unique_ptr<base::OS::MemoryMappedFile> file) : file_(std::move(file)) {} @@ -444,9 +461,11 @@ std::unordered_set<std::shared_ptr<Worker>> Shell::running_workers_; std::atomic<bool> Shell::script_executed_{false}; base::LazyMutex Shell::isolate_status_lock_; std::map<v8::Isolate*, bool> Shell::isolate_status_; +std::map<v8::Isolate*, int> Shell::isolate_running_streaming_tasks_; base::LazyMutex Shell::cached_code_mutex_; std::map<std::string, std::unique_ptr<ScriptCompiler::CachedData>> Shell::cached_code_map_; +std::atomic<int> Shell::unhandled_promise_rejections_{0}; Global<Context> Shell::evaluation_context_; ArrayBuffer::Allocator* Shell::array_buffer_allocator; @@ -486,6 +505,61 @@ void Shell::StoreInCodeCache(Isolate* isolate, Local<Value> source, ScriptCompiler::CachedData::BufferOwned)); } +// Dummy external source stream which returns the whole source in one go. +// TODO(leszeks): Also test chunking the data. +class DummySourceStream : public v8::ScriptCompiler::ExternalSourceStream { + public: + explicit DummySourceStream(Local<String> source) : done_(false) { + source_buffer_ = Utils::OpenHandle(*source)->ToCString( + i::ALLOW_NULLS, i::FAST_STRING_TRAVERSAL, &source_length_); + } + + size_t GetMoreData(const uint8_t** src) override { + if (done_) { + return 0; + } + *src = reinterpret_cast<uint8_t*>(source_buffer_.release()); + done_ = true; + + return source_length_; + } + + private: + int source_length_; + std::unique_ptr<char[]> source_buffer_; + bool done_; +}; + +class StreamingCompileTask final : public v8::Task { + public: + StreamingCompileTask(Isolate* isolate, + v8::ScriptCompiler::StreamedSource* streamed_source) + : isolate_(isolate), + script_streaming_task_(v8::ScriptCompiler::StartStreamingScript( + isolate, streamed_source)) { + Shell::NotifyStartStreamingTask(isolate_); + } + + void Run() override { + script_streaming_task_->Run(); + // Signal that the task has finished using the task runner to wake the + // message loop. + Shell::PostForegroundTask(isolate_, std::make_unique<FinishTask>(isolate_)); + } + + private: + class FinishTask final : public v8::Task { + public: + explicit FinishTask(Isolate* isolate) : isolate_(isolate) {} + void Run() final { Shell::NotifyFinishStreamingTask(isolate_); } + Isolate* isolate_; + }; + + Isolate* isolate_; + std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> + script_streaming_task_; +}; + // Executes a string within the current v8 context. bool Shell::ExecuteString(Isolate* isolate, Local<String> source, Local<Value> name, PrintResult print_result, @@ -512,7 +586,12 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source, i::Handle<i::Script> script = parse_info.CreateScript( i_isolate, str, i::kNullMaybeHandle, ScriptOriginOptions()); - if (!i::parsing::ParseProgram(&parse_info, script, i_isolate)) { + if (!i::parsing::ParseProgram(&parse_info, script, i_isolate, + i::parsing::ReportStatisticsMode::kYes)) { + parse_info.pending_error_handler()->PrepareErrors( + i_isolate, parse_info.ast_value_factory()); + parse_info.pending_error_handler()->ReportErrors(i_isolate, script); + fprintf(stderr, "Failed parsing\n"); return false; } @@ -547,6 +626,19 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source, maybe_script = ScriptCompiler::Compile( context, &script_source, ScriptCompiler::kNoCompileOptions); } + } else if (options.streaming_compile) { + v8::ScriptCompiler::StreamedSource streamed_source( + std::make_unique<DummySourceStream>(source), + v8::ScriptCompiler::StreamedSource::UTF8); + + PostBlockingBackgroundTask( + std::make_unique<StreamingCompileTask>(isolate, &streamed_source)); + + // Pump the loop until the streaming task completes. + Shell::CompleteMessageLoop(isolate); + + maybe_script = + ScriptCompiler::Compile(context, &streamed_source, source, origin); } else { ScriptCompiler::Source script_source(source, origin); maybe_script = ScriptCompiler::Compile(context, &script_source, @@ -575,7 +667,10 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source, StoreInCodeCache(isolate, source, cached_data); delete cached_data; } - if (process_message_queue && !EmptyMessageQueues(isolate)) success = false; + if (process_message_queue) { + if (!EmptyMessageQueues(isolate)) success = false; + if (!HandleUnhandledPromiseRejections(isolate)) success = false; + } data->realm_current_ = data->realm_switch_; } Local<Value> result; @@ -1071,6 +1166,45 @@ MaybeLocal<Context> PerIsolateData::GetTimeoutContext() { return result; } +void PerIsolateData::RemoveUnhandledPromise(Local<Promise> promise) { + // Remove handled promises from the list + DCHECK_EQ(promise->GetIsolate(), isolate_); + for (auto it = unhandled_promises_.begin(); it != unhandled_promises_.end(); + ++it) { + v8::Local<v8::Promise> unhandled_promise = std::get<0>(*it).Get(isolate_); + if (unhandled_promise == promise) { + unhandled_promises_.erase(it--); + } + } +} + +void PerIsolateData::AddUnhandledPromise(Local<Promise> promise, + Local<Message> message, + Local<Value> exception) { + DCHECK_EQ(promise->GetIsolate(), isolate_); + unhandled_promises_.push_back( + std::make_tuple(v8::Global<v8::Promise>(isolate_, promise), + v8::Global<v8::Message>(isolate_, message), + v8::Global<v8::Value>(isolate_, exception))); +} + +size_t PerIsolateData::GetUnhandledPromiseCount() { + return unhandled_promises_.size(); +} + +int PerIsolateData::HandleUnhandledPromiseRejections() { + int unhandled_promises_count = 0; + v8::HandleScope scope(isolate_); + for (auto& tuple : unhandled_promises_) { + Local<v8::Message> message = std::get<1>(tuple).Get(isolate_); + Local<v8::Value> value = std::get<2>(tuple).Get(isolate_); + Shell::ReportException(isolate_, message, value); + unhandled_promises_count++; + } + unhandled_promises_.clear(); + return unhandled_promises_count; +} + PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) { data_->realm_count_ = 1; data_->realm_current_ = 0; @@ -1326,8 +1460,10 @@ void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) { Throw(args.GetIsolate(), "Invalid argument"); return; } + ScriptOrigin origin(String::NewFromUtf8Literal(isolate, "(d8)", + NewStringType::kInternalized)); ScriptCompiler::Source script_source( - args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked()); + args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked(), origin); Local<UnboundScript> script; if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source) .ToLocal(&script)) { @@ -1694,6 +1830,57 @@ void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) { .ToLocalChecked()); } +#ifdef V8_FUZZILLI + +// We have to assume that the fuzzer will be able to call this function e.g. by +// enumerating the properties of the global object and eval'ing them. As such +// this function is implemented in a way that requires passing some magic value +// as first argument (with the idea being that the fuzzer won't be able to +// generate this value) which then also acts as a selector for the operation +// to perform. +void Shell::Fuzzilli(const v8::FunctionCallbackInfo<v8::Value>& args) { + HandleScope handle_scope(args.GetIsolate()); + + String::Utf8Value operation(args.GetIsolate(), args[0]); + if (*operation == nullptr) { + return; + } + + if (strcmp(*operation, "FUZZILLI_CRASH") == 0) { + auto arg = args[1] + ->Int32Value(args.GetIsolate()->GetCurrentContext()) + .FromMaybe(0); + switch (arg) { + case 0: + V8_IMMEDIATE_CRASH(); + break; + case 1: + CHECK(0); + break; + default: + DCHECK(false); + break; + } + } else if (strcmp(*operation, "FUZZILLI_PRINT") == 0) { + static FILE* fzliout = fdopen(REPRL_DWFD, "w"); + if (!fzliout) { + fprintf( + stderr, + "Fuzzer output channel not available, printing to stdout instead\n"); + fzliout = stdout; + } + + String::Utf8Value string(args.GetIsolate(), args[1]); + if (*string == nullptr) { + return; + } + fprintf(fzliout, "%s\n", *string); + fflush(fzliout); + } +} + +#endif // V8_FUZZILLI + void Shell::ReportException(Isolate* isolate, Local<v8::Message> message, Local<v8::Value> exception_obj) { HandleScope handle_scope(isolate); @@ -1958,6 +2145,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) { AddOSMethods(isolate, os_templ); global_template->Set(isolate, "os", os_templ); +#ifdef V8_FUZZILLI + global_template->Set( + String::NewFromUtf8(isolate, "fuzzilli", NewStringType::kNormal) + .ToLocalChecked(), + FunctionTemplate::New(isolate, Fuzzilli), PropertyAttribute::DontEnum); +#endif // V8_FUZZILLI + if (i::FLAG_expose_async_hooks) { Local<ObjectTemplate> async_hooks_templ = ObjectTemplate::New(isolate); async_hooks_templ->Set( @@ -2009,8 +2203,50 @@ static void PrintMessageCallback(Local<Message> message, Local<Value> error) { printf("%s:%i: %s\n", filename_string, linenum, msg_string); } +void Shell::PromiseRejectCallback(v8::PromiseRejectMessage data) { + if (options.ignore_unhandled_promises) return; + if (data.GetEvent() == v8::kPromiseRejectAfterResolved || + data.GetEvent() == v8::kPromiseResolveAfterResolved) { + // Ignore reject/resolve after resolved. + return; + } + v8::Local<v8::Promise> promise = data.GetPromise(); + v8::Isolate* isolate = promise->GetIsolate(); + PerIsolateData* isolate_data = PerIsolateData::Get(isolate); + + if (data.GetEvent() == v8::kPromiseHandlerAddedAfterReject) { + isolate_data->RemoveUnhandledPromise(promise); + return; + } + + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + bool capture_exceptions = + i_isolate->get_capture_stack_trace_for_uncaught_exceptions(); + isolate->SetCaptureStackTraceForUncaughtExceptions(true); + v8::Local<Value> exception = data.GetValue(); + v8::Local<Message> message; + // Assume that all objects are stack-traces. + if (exception->IsObject()) { + message = v8::Exception::CreateMessage(isolate, exception); + } + if (!exception->IsNativeError() && + (message.IsEmpty() || message->GetStackTrace().IsEmpty())) { + // If there is no real Error object, manually throw and catch a stack trace. + v8::TryCatch try_catch(isolate); + try_catch.SetVerbose(true); + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8Literal(isolate, "Unhandled Promise."))); + message = try_catch.Message(); + exception = try_catch.Exception(); + } + isolate->SetCaptureStackTraceForUncaughtExceptions(capture_exceptions); + + isolate_data->AddUnhandledPromise(promise, message, exception); +} + void Shell::Initialize(Isolate* isolate, D8Console* console, bool isOnMainThread) { + isolate->SetPromiseRejectCallback(PromiseRejectCallback); if (isOnMainThread) { // Set up counters if (i::FLAG_map_counters[0] != '\0') { @@ -2029,6 +2265,19 @@ void Shell::Initialize(Isolate* isolate, D8Console* console, isolate->SetHostInitializeImportMetaObjectCallback( Shell::HostInitializeImportMetaObject); +#ifdef V8_FUZZILLI + // Let the parent process (Fuzzilli) know we are ready. + char helo[] = "HELO"; + if (write(REPRL_CWFD, helo, 4) != 4 || read(REPRL_CRFD, helo, 4) != 4) { + fuzzilli_reprl = false; + } + + if (memcmp(helo, "HELO", 4) != 0) { + fprintf(stderr, "Invalid response from parent\n"); + _exit(-1); + } +#endif // V8_FUZZILLI + debug::SetConsoleDelegate(isolate, console); } @@ -2167,11 +2416,6 @@ void Shell::WriteLcovData(v8::Isolate* isolate, const char* file) { } void Shell::OnExit(v8::Isolate* isolate) { - // Dump basic block profiling data. - if (i::FLAG_turbo_profiling) { - i::BasicBlockProfiler* profiler = i::BasicBlockProfiler::Get(); - i::StdoutStream{} << *profiler; - } isolate->Dispose(); if (i::FLAG_dump_counters || i::FLAG_dump_counters_nvp) { @@ -2518,6 +2762,36 @@ bool ends_with(const char* input, const char* suffix) { bool SourceGroup::Execute(Isolate* isolate) { bool success = true; +#ifdef V8_FUZZILLI + HandleScope handle_scope(isolate); + Local<String> file_name = + String::NewFromUtf8(isolate, "fuzzcode.js", NewStringType::kNormal) + .ToLocalChecked(); + + size_t script_size; + CHECK_EQ(read(REPRL_CRFD, &script_size, 8), 8); + char* buffer = new char[script_size + 1]; + char* ptr = buffer; + size_t remaining = script_size; + while (remaining > 0) { + ssize_t rv = read(REPRL_DRFD, ptr, remaining); + CHECK_GE(rv, 0); + remaining -= rv; + ptr += rv; + } + buffer[script_size] = 0; + + Local<String> source = + String::NewFromUtf8(isolate, buffer, NewStringType::kNormal) + .ToLocalChecked(); + delete[] buffer; + Shell::set_script_executed(); + if (!Shell::ExecuteString(isolate, source, file_name, Shell::kNoPrintResult, + Shell::kReportExceptions, + Shell::kNoProcessMessageQueue)) { + return false; + } +#endif // V8_FUZZILLI for (int i = begin_offset_; i < end_offset_; ++i) { const char* arg = argv_[i]; if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) { @@ -2780,9 +3054,7 @@ void Worker::ExecuteInThread() { in_semaphore_.Wait(); std::unique_ptr<SerializationData> data; if (!in_queue_.Dequeue(&data)) continue; - if (!data) { - break; - } + if (!data) break; v8::TryCatch try_catch(isolate); try_catch.SetVerbose(true); HandleScope scope(isolate); @@ -2795,6 +3067,7 @@ void Worker::ExecuteInThread() { USE(result); } } + // TODO(cbruni): Check for unhandled promises here. } } } @@ -2895,6 +3168,9 @@ bool Shell::SetOptions(int argc, char* argv[]) { // Ignore any -f flags for compatibility with other stand-alone // JavaScript engines. continue; + } else if (strcmp(argv[i], "--ignore-unhandled-promises") == 0) { + options.ignore_unhandled_promises = true; + argv[i] = nullptr; } else if (strcmp(argv[i], "--isolate") == 0) { options.num_isolates++; } else if (strcmp(argv[i], "--throws") == 0) { @@ -2935,6 +3211,13 @@ bool Shell::SetOptions(int argc, char* argv[]) { return false; } argv[i] = nullptr; + } else if (strcmp(argv[i], "--streaming-compile") == 0) { + options.streaming_compile = true; + argv[i] = nullptr; + } else if ((strcmp(argv[i], "--no-streaming-compile") == 0) || + (strcmp(argv[i], "--nostreaming-compile") == 0)) { + options.streaming_compile = false; + argv[i] = nullptr; } else if (strcmp(argv[i], "--enable-tracing") == 0) { options.trace_enabled = true; argv[i] = nullptr; @@ -3045,6 +3328,7 @@ int Shell::RunMain(Isolate* isolate, bool last_run) { PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate)); if (!options.isolate_sources[0].Execute(isolate)) success = false; if (!CompleteMessageLoop(isolate)) success = false; + if (!HandleUnhandledPromiseRejections(isolate)) success = false; } if (!use_existing_context) { DisposeModuleEmbedderData(context); @@ -3072,6 +3356,11 @@ int Shell::RunMain(Isolate* isolate, bool last_run) { } } WaitForRunningWorkers(); + if (Shell::unhandled_promise_rejections_.load() > 0) { + printf("%i pending unhandled Promise rejection(s) detected.\n", + Shell::unhandled_promise_rejections_.load()); + success = false; + } // In order to finish successfully, success must be != expected_to_throw. return success == Shell::options.expected_to_throw ? 1 : 0; } @@ -3093,11 +3382,20 @@ void Shell::CollectGarbage(Isolate* isolate) { void Shell::SetWaitUntilDone(Isolate* isolate, bool value) { base::MutexGuard guard(isolate_status_lock_.Pointer()); - if (isolate_status_.count(isolate) == 0) { - isolate_status_.insert(std::make_pair(isolate, value)); - } else { - isolate_status_[isolate] = value; - } + isolate_status_[isolate] = value; +} + +void Shell::NotifyStartStreamingTask(Isolate* isolate) { + DCHECK(options.streaming_compile); + base::MutexGuard guard(isolate_status_lock_.Pointer()); + ++isolate_running_streaming_tasks_[isolate]; +} + +void Shell::NotifyFinishStreamingTask(Isolate* isolate) { + DCHECK(options.streaming_compile); + base::MutexGuard guard(isolate_status_lock_.Pointer()); + --isolate_running_streaming_tasks_[isolate]; + DCHECK_GE(isolate_running_streaming_tasks_[isolate], 0); } namespace { @@ -3163,7 +3461,8 @@ bool Shell::CompleteMessageLoop(Isolate* isolate) { i::wasm::WasmEngine* wasm_engine = i_isolate->wasm_engine(); bool should_wait = (options.wait_for_wasm && wasm_engine->HasRunningCompileJob(i_isolate)) || - isolate_status_[isolate]; + isolate_status_[isolate] || + isolate_running_streaming_tasks_[isolate] > 0; return should_wait ? platform::MessageLoopBehavior::kWaitForWork : platform::MessageLoopBehavior::kDoNotWait; }; @@ -3175,6 +3474,24 @@ bool Shell::EmptyMessageQueues(Isolate* isolate) { isolate, []() { return platform::MessageLoopBehavior::kDoNotWait; }); } +void Shell::PostForegroundTask(Isolate* isolate, std::unique_ptr<Task> task) { + g_default_platform->GetForegroundTaskRunner(isolate)->PostTask( + std::move(task)); +} + +void Shell::PostBlockingBackgroundTask(std::unique_ptr<Task> task) { + g_default_platform->CallBlockingTaskOnWorkerThread(std::move(task)); +} + +bool Shell::HandleUnhandledPromiseRejections(Isolate* isolate) { + if (options.ignore_unhandled_promises) return true; + PerIsolateData* data = PerIsolateData::Get(isolate); + int count = data->HandleUnhandledPromiseRejections(); + Shell::unhandled_promise_rejections_.store( + Shell::unhandled_promise_rejections_.load() + count); + return count == 0; +} + class Serializer : public ValueSerializer::Delegate { public: explicit Serializer(Isolate* isolate) @@ -3505,8 +3822,14 @@ int Shell::Main(int argc, char* argv[]) { std::ofstream trace_file; if (options.trace_enabled && !i::FLAG_verify_predictable) { tracing = std::make_unique<platform::tracing::TracingController>(); - trace_file.open(options.trace_path ? options.trace_path : "v8_trace.json"); - DCHECK(trace_file.good()); + const char* trace_path = + options.trace_path ? options.trace_path : "v8_trace.json"; + trace_file.open(trace_path); + if (!trace_file.good()) { + printf("Cannot open trace file '%s' for writing: %s.\n", trace_path, + strerror(errno)); + return 1; + } #ifdef V8_USE_PERFETTO // Set up the in-process backend that the tracing controller will connect @@ -3611,112 +3934,140 @@ int Shell::Main(int argc, char* argv[]) { Initialize(isolate, &console); PerIsolateData data(isolate); - if (options.trace_enabled) { - platform::tracing::TraceConfig* trace_config; - if (options.trace_config) { - int size = 0; - char* trace_config_json_str = ReadChars(options.trace_config, &size); - trace_config = - tracing::CreateTraceConfigFromJSON(isolate, trace_config_json_str); - delete[] trace_config_json_str; - } else { - trace_config = - platform::tracing::TraceConfig::CreateDefaultTraceConfig(); + // Fuzzilli REPRL = read-eval-print-loop + do { +#ifdef V8_FUZZILLI + if (fuzzilli_reprl) { + unsigned action = 0; + ssize_t nread = read(REPRL_CRFD, &action, 4); + if (nread != 4 || action != 'cexe') { + fprintf(stderr, "Unknown action: %u\n", action); + _exit(-1); + } + } +#endif // V8_FUZZILLI + + result = 0; + + if (options.trace_enabled) { + platform::tracing::TraceConfig* trace_config; + if (options.trace_config) { + int size = 0; + char* trace_config_json_str = ReadChars(options.trace_config, &size); + trace_config = tracing::CreateTraceConfigFromJSON( + isolate, trace_config_json_str); + delete[] trace_config_json_str; + } else { + trace_config = + platform::tracing::TraceConfig::CreateDefaultTraceConfig(); + } + tracing_controller->StartTracing(trace_config); } - tracing_controller->StartTracing(trace_config); - } - - CpuProfiler* cpu_profiler; - if (options.cpu_profiler) { - cpu_profiler = CpuProfiler::New(isolate); - CpuProfilingOptions profile_options; - cpu_profiler->StartProfiling(String::Empty(isolate), profile_options); - } - if (options.stress_opt) { - options.stress_runs = D8Testing::GetStressRuns(); - for (int i = 0; i < options.stress_runs && result == 0; i++) { - printf("============ Stress %d/%d ============\n", i + 1, - options.stress_runs); - D8Testing::PrepareStressRun(i); - bool last_run = i == options.stress_runs - 1; - result = RunMain(isolate, last_run); + CpuProfiler* cpu_profiler; + if (options.cpu_profiler) { + cpu_profiler = CpuProfiler::New(isolate); + CpuProfilingOptions profile_options; + cpu_profiler->StartProfiling(String::Empty(isolate), profile_options); } - printf("======== Full Deoptimization =======\n"); - D8Testing::DeoptimizeAll(isolate); - } else if (i::FLAG_stress_runs > 0) { - options.stress_runs = i::FLAG_stress_runs; - for (int i = 0; i < options.stress_runs && result == 0; i++) { - printf("============ Run %d/%d ============\n", i + 1, - options.stress_runs); - bool last_run = i == options.stress_runs - 1; + + if (options.stress_opt) { + options.stress_runs = D8Testing::GetStressRuns(); + for (int i = 0; i < options.stress_runs && result == 0; i++) { + printf("============ Stress %d/%d ============\n", i + 1, + options.stress_runs); + D8Testing::PrepareStressRun(i); + bool last_run = i == options.stress_runs - 1; + result = RunMain(isolate, last_run); + } + printf("======== Full Deoptimization =======\n"); + D8Testing::DeoptimizeAll(isolate); + } else if (i::FLAG_stress_runs > 0) { + options.stress_runs = i::FLAG_stress_runs; + for (int i = 0; i < options.stress_runs && result == 0; i++) { + printf("============ Run %d/%d ============\n", i + 1, + options.stress_runs); + bool last_run = i == options.stress_runs - 1; + result = RunMain(isolate, last_run); + } + } else if (options.code_cache_options != + ShellOptions::CodeCacheOptions::kNoProduceCache) { + printf("============ Run: Produce code cache ============\n"); + // First run to produce the cache + Isolate::CreateParams create_params; + create_params.array_buffer_allocator = Shell::array_buffer_allocator; + i::FLAG_hash_seed ^= 1337; // Use a different hash seed. + Isolate* isolate2 = Isolate::New(create_params); + i::FLAG_hash_seed ^= 1337; // Restore old hash seed. + { + D8Console console(isolate2); + Initialize(isolate2, &console); + PerIsolateData data(isolate2); + Isolate::Scope isolate_scope(isolate2); + + result = RunMain(isolate2, false); + } + isolate2->Dispose(); + + // Change the options to consume cache + DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile || + options.compile_options == + v8::ScriptCompiler::kNoCompileOptions); + options.compile_options = v8::ScriptCompiler::kConsumeCodeCache; + options.code_cache_options = + ShellOptions::CodeCacheOptions::kNoProduceCache; + + printf("============ Run: Consume code cache ============\n"); + // Second run to consume the cache in current isolate + result = RunMain(isolate, true); + options.compile_options = v8::ScriptCompiler::kNoCompileOptions; + } else { + bool last_run = true; result = RunMain(isolate, last_run); } - } else if (options.code_cache_options != - ShellOptions::CodeCacheOptions::kNoProduceCache) { - printf("============ Run: Produce code cache ============\n"); - // First run to produce the cache - Isolate::CreateParams create_params; - create_params.array_buffer_allocator = Shell::array_buffer_allocator; - i::FLAG_hash_seed ^= 1337; // Use a different hash seed. - Isolate* isolate2 = Isolate::New(create_params); - i::FLAG_hash_seed ^= 1337; // Restore old hash seed. - { - D8Console console(isolate2); - Initialize(isolate2, &console); - PerIsolateData data(isolate2); - Isolate::Scope isolate_scope(isolate2); - result = RunMain(isolate2, false); + // Run interactive shell if explicitly requested or if no script has been + // executed, but never on --test + if (use_interactive_shell()) { + RunShell(isolate); } - isolate2->Dispose(); - - // Change the options to consume cache - DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile || - options.compile_options == v8::ScriptCompiler::kNoCompileOptions); - options.compile_options = v8::ScriptCompiler::kConsumeCodeCache; - options.code_cache_options = - ShellOptions::CodeCacheOptions::kNoProduceCache; - - printf("============ Run: Consume code cache ============\n"); - // Second run to consume the cache in current isolate - result = RunMain(isolate, true); - options.compile_options = v8::ScriptCompiler::kNoCompileOptions; - } else { - bool last_run = true; - result = RunMain(isolate, last_run); - } - // Run interactive shell if explicitly requested or if no script has been - // executed, but never on --test - if (use_interactive_shell()) { - RunShell(isolate); - } - - if (i::FLAG_trace_ignition_dispatches && - i::FLAG_trace_ignition_dispatches_output_file != nullptr) { - WriteIgnitionDispatchCountersFile(isolate); - } + if (i::FLAG_trace_ignition_dispatches && + i::FLAG_trace_ignition_dispatches_output_file != nullptr) { + WriteIgnitionDispatchCountersFile(isolate); + } - if (options.cpu_profiler) { - CpuProfile* profile = cpu_profiler->StopProfiling(String::Empty(isolate)); - if (options.cpu_profiler_print) { - const internal::ProfileNode* root = - reinterpret_cast<const internal::ProfileNode*>( - profile->GetTopDownRoot()); - root->Print(0); + if (options.cpu_profiler) { + CpuProfile* profile = + cpu_profiler->StopProfiling(String::Empty(isolate)); + if (options.cpu_profiler_print) { + const internal::ProfileNode* root = + reinterpret_cast<const internal::ProfileNode*>( + profile->GetTopDownRoot()); + root->Print(0); + } + profile->Delete(); + cpu_profiler->Dispose(); } - profile->Delete(); - cpu_profiler->Dispose(); - } - // Shut down contexts and collect garbage. - cached_code_map_.clear(); - evaluation_context_.Reset(); - stringify_function_.Reset(); - CollectGarbage(isolate); + // Shut down contexts and collect garbage. + cached_code_map_.clear(); + evaluation_context_.Reset(); + stringify_function_.Reset(); + CollectGarbage(isolate); + +#ifdef V8_FUZZILLI + // Send result to parent (fuzzilli) and reset edge guards. + if (fuzzilli_reprl) { + int status = result << 8; + CHECK_EQ(write(REPRL_CWFD, &status, 4), 4); + __sanitizer_cov_reset_edgeguards(); + } +#endif // V8_FUZZILLI + } while (fuzzilli_reprl); } OnExit(isolate); + V8::Dispose(); V8::ShutdownPlatform(); |