diff --git a/src/base/platform/platform-posix.cc b/src/base/platform/platform-posix.cc index b469f6254f..9f590d637e 100644 --- a/src/base/platform/platform-posix.cc +++ b/src/base/platform/platform-posix.cc @@ -679,9 +679,7 @@ FILE* OS::OpenTemporaryFile() { return tmpfile(); } - -const char* const OS::LogFileOpenMode = "w"; - +const char* const OS::LogFileOpenMode = "w+"; void OS::Print(const char* format, ...) { va_list args; diff --git a/src/base/platform/platform-win32.cc b/src/base/platform/platform-win32.cc index 6821ca9102..3eb11d88f5 100644 --- a/src/base/platform/platform-win32.cc +++ b/src/base/platform/platform-win32.cc @@ -603,8 +603,7 @@ FILE* OS::OpenTemporaryFile() { // Open log file in binary mode to avoid /n -> /r/n conversion. -const char* const OS::LogFileOpenMode = "wb"; - +const char* const OS::LogFileOpenMode = "wb+"; // Print (debug) message to console. void OS::Print(const char* format, ...) { diff --git a/src/d8/d8.cc b/src/d8/d8.cc index 26ccb62c68..fb24b377ef 100644 --- a/src/d8/d8.cc +++ b/src/d8/d8.cc @@ -43,6 +43,7 @@ #include "src/init/v8.h" #include "src/interpreter/interpreter.h" #include "src/logging/counters.h" +#include "src/logging/log-utils.h" #include "src/objects/managed.h" #include "src/objects/objects-inl.h" #include "src/objects/objects.h" @@ -1503,6 +1504,41 @@ void Shell::RealmSharedSet(Local property, Local value, data->realm_shared_.Reset(isolate, value); } +void Shell::LogGetAndStop(const v8::FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + i::Isolate* i_isolate = reinterpret_cast(isolate); + HandleScope handle_scope(isolate); + + std::string file_name = i_isolate->logger()->file_name(); + if (i::Log::IsLoggingToConsole(file_name)) { + Throw(isolate, "Logging to console instead of file."); + return; + } + if (!i_isolate->logger()->is_logging()) { + Throw(isolate, "Logging not enabled."); + return; + } + + std::string raw_log; + FILE* log_file = i_isolate->logger()->TearDownAndGetLogFile(); + CHECK_NOT_NULL(log_file); + + bool exists = false; + raw_log = i::ReadFile(log_file, &exists, true); + fclose(log_file); + + if (!exists) { + Throw(isolate, "Unable to read log file."); + return; + } + Local result = + String::NewFromUtf8(isolate, raw_log.c_str(), NewStringType::kNormal, + static_cast(raw_log.size())) + .ToLocalChecked(); + + args.GetReturnValue().Set(result); +} + // async_hooks.createHook() registers functions to be called for different // lifetime events of each async operation. void Shell::AsyncHooksCreateHook( @@ -2071,6 +2107,11 @@ Local Shell::Stringify(Isolate* isolate, Local value) { Local Shell::CreateGlobalTemplate(Isolate* isolate) { Local global_template = ObjectTemplate::New(isolate); + global_template->Set(Symbol::GetToStringTag(isolate), + String::NewFromUtf8Literal(isolate, "global")); + global_template->Set(isolate, "version", + FunctionTemplate::New(isolate, Version)); + global_template->Set(isolate, "print", FunctionTemplate::New(isolate, Print)); global_template->Set(isolate, "printErr", FunctionTemplate::New(isolate, PrintErr)); @@ -2089,57 +2130,37 @@ Local Shell::CreateGlobalTemplate(Isolate* isolate) { if (!options.omit_quit) { global_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit)); } - Local test_template = ObjectTemplate::New(isolate); - global_template->Set(isolate, "testRunner", test_template); - test_template->Set(isolate, "notifyDone", - FunctionTemplate::New(isolate, NotifyDone)); - test_template->Set(isolate, "waitUntilDone", - FunctionTemplate::New(isolate, WaitUntilDone)); - // Reliable access to quit functionality. The "quit" method function - // installed on the global object can be hidden with the --omit-quit flag - // (e.g. on asan bots). - test_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit)); + global_template->Set(isolate, "testRunner", + Shell::CreateTestRunnerTemplate(isolate)); + global_template->Set(isolate, "Realm", Shell::CreateRealmTemplate(isolate)); + global_template->Set(isolate, "performance", + Shell::CreatePerformanceTemplate(isolate)); + global_template->Set(isolate, "Worker", Shell::CreateWorkerTemplate(isolate)); + global_template->Set(isolate, "os", Shell::CreateOSTemplate(isolate)); + global_template->Set(isolate, "d8", Shell::CreateD8Template(isolate)); - global_template->Set(isolate, "version", - FunctionTemplate::New(isolate, Version)); - global_template->Set(Symbol::GetToStringTag(isolate), - String::NewFromUtf8Literal(isolate, "global")); +#ifdef V8_FUZZILLI + global_template->Set( + String::NewFromUtf8(isolate, "fuzzilli", NewStringType::kNormal) + .ToLocalChecked(), + FunctionTemplate::New(isolate, Fuzzilli), PropertyAttribute::DontEnum); +#endif // V8_FUZZILLI - // Bind the Realm object. - Local realm_template = ObjectTemplate::New(isolate); - realm_template->Set(isolate, "current", - FunctionTemplate::New(isolate, RealmCurrent)); - realm_template->Set(isolate, "owner", - FunctionTemplate::New(isolate, RealmOwner)); - realm_template->Set(isolate, "global", - FunctionTemplate::New(isolate, RealmGlobal)); - realm_template->Set(isolate, "create", - FunctionTemplate::New(isolate, RealmCreate)); - realm_template->Set( - isolate, "createAllowCrossRealmAccess", - FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess)); - realm_template->Set(isolate, "navigate", - FunctionTemplate::New(isolate, RealmNavigate)); - realm_template->Set(isolate, "detachGlobal", - FunctionTemplate::New(isolate, RealmDetachGlobal)); - realm_template->Set(isolate, "dispose", - FunctionTemplate::New(isolate, RealmDispose)); - realm_template->Set(isolate, "switch", - FunctionTemplate::New(isolate, RealmSwitch)); - realm_template->Set(isolate, "eval", - FunctionTemplate::New(isolate, RealmEval)); - realm_template->SetAccessor(String::NewFromUtf8Literal(isolate, "shared"), - RealmSharedGet, RealmSharedSet); - global_template->Set(isolate, "Realm", realm_template); + if (i::FLAG_expose_async_hooks) { + global_template->Set(isolate, "async_hooks", + Shell::CreateAsyncHookTemplate(isolate)); + } - Local performance_template = ObjectTemplate::New(isolate); - performance_template->Set(isolate, "now", - FunctionTemplate::New(isolate, PerformanceNow)); - performance_template->Set( - isolate, "measureMemory", - FunctionTemplate::New(isolate, PerformanceMeasureMemory)); - global_template->Set(isolate, "performance", performance_template); + return global_template; +} +Local Shell::CreateOSTemplate(Isolate* isolate) { + Local os_template = ObjectTemplate::New(isolate); + AddOSMethods(isolate, os_template); + return os_template; +} + +Local Shell::CreateWorkerTemplate(Isolate* isolate) { Local worker_fun_template = FunctionTemplate::New(isolate, WorkerNew); Local worker_signature = @@ -2164,34 +2185,83 @@ Local Shell::CreateGlobalTemplate(Isolate* isolate) { FunctionTemplate::New(isolate, WorkerGetMessage, Local(), worker_signature)); worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1); - global_template->Set(isolate, "Worker", worker_fun_template); + return worker_fun_template; +} - Local os_templ = ObjectTemplate::New(isolate); - AddOSMethods(isolate, os_templ); - global_template->Set(isolate, "os", os_templ); +Local Shell::CreateAsyncHookTemplate(Isolate* isolate) { + Local async_hooks_templ = ObjectTemplate::New(isolate); + async_hooks_templ->Set(isolate, "createHook", + FunctionTemplate::New(isolate, AsyncHooksCreateHook)); + async_hooks_templ->Set( + isolate, "executionAsyncId", + FunctionTemplate::New(isolate, AsyncHooksExecutionAsyncId)); + async_hooks_templ->Set( + isolate, "triggerAsyncId", + FunctionTemplate::New(isolate, AsyncHooksTriggerAsyncId)); + return async_hooks_templ; +} -#ifdef V8_FUZZILLI - global_template->Set( - String::NewFromUtf8(isolate, "fuzzilli", NewStringType::kNormal) - .ToLocalChecked(), - FunctionTemplate::New(isolate, Fuzzilli), PropertyAttribute::DontEnum); -#endif // V8_FUZZILLI +Local Shell::CreateTestRunnerTemplate(Isolate* isolate) { + Local test_template = ObjectTemplate::New(isolate); + test_template->Set(isolate, "notifyDone", + FunctionTemplate::New(isolate, NotifyDone)); + test_template->Set(isolate, "waitUntilDone", + FunctionTemplate::New(isolate, WaitUntilDone)); + // Reliable access to quit functionality. The "quit" method function + // installed on the global object can be hidden with the --omit-quit flag + // (e.g. on asan bots). + test_template->Set(isolate, "quit", FunctionTemplate::New(isolate, Quit)); + return test_template; +} - if (i::FLAG_expose_async_hooks) { - Local async_hooks_templ = ObjectTemplate::New(isolate); - async_hooks_templ->Set( - isolate, "createHook", - FunctionTemplate::New(isolate, AsyncHooksCreateHook)); - async_hooks_templ->Set( - isolate, "executionAsyncId", - FunctionTemplate::New(isolate, AsyncHooksExecutionAsyncId)); - async_hooks_templ->Set( - isolate, "triggerAsyncId", - FunctionTemplate::New(isolate, AsyncHooksTriggerAsyncId)); - global_template->Set(isolate, "async_hooks", async_hooks_templ); +Local Shell::CreatePerformanceTemplate(Isolate* isolate) { + Local performance_template = ObjectTemplate::New(isolate); + performance_template->Set(isolate, "now", + FunctionTemplate::New(isolate, PerformanceNow)); + performance_template->Set( + isolate, "measureMemory", + FunctionTemplate::New(isolate, PerformanceMeasureMemory)); + return performance_template; +} + +Local Shell::CreateRealmTemplate(Isolate* isolate) { + Local realm_template = ObjectTemplate::New(isolate); + realm_template->Set(isolate, "current", + FunctionTemplate::New(isolate, RealmCurrent)); + realm_template->Set(isolate, "owner", + FunctionTemplate::New(isolate, RealmOwner)); + realm_template->Set(isolate, "global", + FunctionTemplate::New(isolate, RealmGlobal)); + realm_template->Set(isolate, "create", + FunctionTemplate::New(isolate, RealmCreate)); + realm_template->Set( + isolate, "createAllowCrossRealmAccess", + FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess)); + realm_template->Set(isolate, "navigate", + FunctionTemplate::New(isolate, RealmNavigate)); + realm_template->Set(isolate, "detachGlobal", + FunctionTemplate::New(isolate, RealmDetachGlobal)); + realm_template->Set(isolate, "dispose", + FunctionTemplate::New(isolate, RealmDispose)); + realm_template->Set(isolate, "switch", + FunctionTemplate::New(isolate, RealmSwitch)); + realm_template->Set(isolate, "eval", + FunctionTemplate::New(isolate, RealmEval)); + realm_template->SetAccessor(String::NewFromUtf8Literal(isolate, "shared"), + RealmSharedGet, RealmSharedSet); + return realm_template; +} + +Local Shell::CreateD8Template(Isolate* isolate) { + Local d8_template = ObjectTemplate::New(isolate); + { + Local log_template = ObjectTemplate::New(isolate); + log_template->Set(isolate, "getAndStop", + FunctionTemplate::New(isolate, LogGetAndStop)); + + d8_template->Set(isolate, "log", log_template); } - - return global_template; + return d8_template; } static void PrintMessageCallback(Local message, Local error) { diff --git a/src/d8/d8.h b/src/d8/d8.h index 6b2c08fd6e..83310be4d3 100644 --- a/src/d8/d8.h +++ b/src/d8/d8.h @@ -401,6 +401,8 @@ class Shell : public i::AllStatic { static void RealmSharedSet(Local property, Local value, const PropertyCallbackInfo& info); + static void LogGetAndStop(const v8::FunctionCallbackInfo& args); + static void AsyncHooksCreateHook( const v8::FunctionCallbackInfo& args); static void AsyncHooksExecutionAsyncId( @@ -539,7 +541,16 @@ class Shell : public i::AllStatic { static Local Stringify(Isolate* isolate, Local value); static void RunShell(Isolate* isolate); static bool SetOptions(int argc, char* argv[]); + static Local CreateGlobalTemplate(Isolate* isolate); + static Local CreateOSTemplate(Isolate* isolate); + static Local CreateWorkerTemplate(Isolate* isolate); + static Local CreateAsyncHookTemplate(Isolate* isolate); + static Local CreateTestRunnerTemplate(Isolate* isolate); + static Local CreatePerformanceTemplate(Isolate* isolate); + static Local CreateRealmTemplate(Isolate* isolate); + static Local CreateD8Template(Isolate* isolate); + static MaybeLocal CreateRealm( const v8::FunctionCallbackInfo& args, int index, v8::MaybeLocal global_object); diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc index 8df3c4e4eb..0ed85fbace 100644 --- a/src/execution/isolate.cc +++ b/src/execution/isolate.cc @@ -3077,7 +3077,8 @@ void Isolate::Deinit() { cancelable_task_manager()->CancelAndWait(); heap_.TearDown(); - logger_->TearDown(); + FILE* logfile = logger_->TearDownAndGetLogFile(); + if (logfile != nullptr) fclose(logfile); if (wasm_engine_) { wasm_engine_->RemoveIsolate(this); diff --git a/src/logging/log-utils.cc b/src/logging/log-utils.cc index efe3697b5e..9a329a104d 100644 --- a/src/logging/log-utils.cc +++ b/src/logging/log-utils.cc @@ -23,25 +23,35 @@ const char* const Log::kLogToTemporaryFile = "&"; const char* const Log::kLogToConsole = "-"; // static -FILE* Log::CreateOutputHandle(const char* file_name) { +FILE* Log::CreateOutputHandle(std::string file_name) { // If we're logging anything, we need to open the log file. if (!Log::InitLogAtStart()) { return nullptr; - } else if (strcmp(file_name, kLogToConsole) == 0) { + } else if (Log::IsLoggingToConsole(file_name)) { return stdout; - } else if (strcmp(file_name, kLogToTemporaryFile) == 0) { + } else if (Log::IsLoggingToTemporaryFile(file_name)) { return base::OS::OpenTemporaryFile(); } else { - return base::OS::FOpen(file_name, base::OS::LogFileOpenMode); + return base::OS::FOpen(file_name.c_str(), base::OS::LogFileOpenMode); } } -Log::Log(Logger* logger, const char* file_name) - : output_handle_(Log::CreateOutputHandle(file_name)), +// static +bool Log::IsLoggingToConsole(std::string file_name) { + return file_name.compare(Log::kLogToConsole) == 0; +} + +// static +bool Log::IsLoggingToTemporaryFile(std::string file_name) { + return file_name.compare(Log::kLogToTemporaryFile) == 0; +} + +Log::Log(std::string file_name) + : file_name_(file_name), + output_handle_(Log::CreateOutputHandle(file_name)), os_(output_handle_ == nullptr ? stdout : output_handle_), is_enabled_(output_handle_ != nullptr), - format_buffer_(NewArray(kMessageBufferSize)), - logger_(logger) { + format_buffer_(NewArray(kMessageBufferSize)) { // --log-all enables all the log flags. if (FLAG_log_all) { FLAG_log_api = true; @@ -56,7 +66,13 @@ Log::Log(Logger* logger, const char* file_name) if (FLAG_prof) FLAG_log_code = true; if (output_handle_ == nullptr) return; - Log::MessageBuilder msg(this); + WriteLogHeader(); +} + +void Log::WriteLogHeader() { + std::unique_ptr msg_ptr = NewMessageBuilder(); + if (!msg_ptr) return; + Log::MessageBuilder& msg = *msg_ptr.get(); LogSeparator kNext = LogSeparator::kSeparator; msg << "v8-version" << kNext << Version::GetMajor() << kNext << Version::GetMinor() << kNext << Version::GetBuild() << kNext @@ -83,20 +99,17 @@ FILE* Log::Close() { base::MutexGuard guard(&mutex_); FILE* result = nullptr; if (output_handle_ != nullptr) { - if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) { - fclose(output_handle_); - } else { - result = output_handle_; - } + fflush(output_handle_); + result = output_handle_; } output_handle_ = nullptr; - format_buffer_.reset(); - is_enabled_.store(false, std::memory_order_relaxed); return result; } +std::string Log::file_name() const { return file_name_; } + Log::MessageBuilder::MessageBuilder(Log* log) : log_(log), lock_guard_(&log_->mutex_) { DCHECK_NOT_NULL(log_->format_buffer_.get()); diff --git a/src/logging/log-utils.h b/src/logging/log-utils.h index 1d00923ef7..e35c2deda0 100644 --- a/src/logging/log-utils.h +++ b/src/logging/log-utils.h @@ -30,22 +30,27 @@ enum class LogSeparator { kSeparator }; // Functions and data for performing output of log messages. class Log { public: - Log(Logger* log, const char* log_file_name); + explicit Log(std::string log_file_name); static bool InitLogAtStart() { - return FLAG_log || FLAG_log_api || FLAG_log_code || FLAG_log_handles || - FLAG_log_suspect || FLAG_ll_prof || FLAG_perf_basic_prof || - FLAG_perf_prof || FLAG_log_source_code || FLAG_gdbjit || - FLAG_log_internal_timer_events || FLAG_prof_cpp || FLAG_trace_ic || - FLAG_log_function_events || FLAG_trace_zone_stats || + return FLAG_log || FLAG_log_all || FLAG_log_api || FLAG_log_code || + FLAG_log_handles || FLAG_log_suspect || FLAG_ll_prof || + FLAG_perf_basic_prof || FLAG_perf_prof || FLAG_log_source_code || + FLAG_gdbjit || FLAG_log_internal_timer_events || FLAG_prof_cpp || + FLAG_trace_ic || FLAG_log_function_events || FLAG_trace_zone_stats || FLAG_turbo_profiling_log_builtins; } + V8_EXPORT_PRIVATE static bool IsLoggingToConsole(std::string file_name); + V8_EXPORT_PRIVATE static bool IsLoggingToTemporaryFile(std::string file_name); + // Frees all resources acquired in Initialize and Open... functions. // When a temporary file is used for the log, returns its stream descriptor, // leaving the file open. FILE* Close(); + std::string file_name() const; + // Returns whether logging is enabled. bool IsEnabled() { return is_enabled_.load(std::memory_order_relaxed); } @@ -109,19 +114,15 @@ class Log { std::unique_ptr NewMessageBuilder(); private: - static FILE* CreateOutputHandle(const char* file_name); + static FILE* CreateOutputHandle(std::string file_name); - // Implementation of writing to a log file. - int WriteToFile(const char* msg, int length) { - DCHECK_NOT_NULL(output_handle_); - os_.write(msg, length); - DCHECK(!os_.bad()); - return length; - } + void WriteLogHeader(); + std::string file_name_; // When logging is active output_handle_ is used to store a pointer to log // destination. mutex_ should be acquired before using output_handle_. FILE* output_handle_; + OFStream os_; // Stores whether logging is enabled. @@ -134,10 +135,6 @@ class Log { // Buffer used for formatting log messages. This is a singleton buffer and // mutex_ should be acquired before using it. std::unique_ptr format_buffer_; - - Logger* logger_; - - friend class Logger; }; template <> diff --git a/src/logging/log.cc b/src/logging/log.cc index 6ff7f76697..833a9ee604 100644 --- a/src/logging/log.cc +++ b/src/logging/log.cc @@ -1974,16 +1974,13 @@ void Logger::LogAllMaps() { } } -static void AddIsolateIdIfNeeded(std::ostream& os, // NOLINT - Isolate* isolate) { - if (FLAG_logfile_per_isolate) { - os << "isolate-" << isolate << "-" << base::OS::GetCurrentProcessId() - << "-"; - } +static void AddIsolateIdIfNeeded(std::ostream& os, Isolate* isolate) { + if (!FLAG_logfile_per_isolate) return; + os << "isolate-" << isolate << "-" << base::OS::GetCurrentProcessId() << "-"; } -static void PrepareLogFileName(std::ostream& os, // NOLINT - Isolate* isolate, const char* file_name) { +static void PrepareLogFileName(std::ostream& os, Isolate* isolate, + const char* file_name) { int dir_separator_count = 0; for (const char* p = file_name; *p; p++) { if (base::OS::isDirectorySeparator(*p)) dir_separator_count++; @@ -2032,9 +2029,8 @@ bool Logger::SetUp(Isolate* isolate) { is_initialized_ = true; std::ostringstream log_file_name; - std::ostringstream source_log_file_name; PrepareLogFileName(log_file_name, isolate, FLAG_logfile); - log_ = std::make_unique(this, log_file_name.str().c_str()); + log_ = std::make_unique(log_file_name.str()); #if V8_OS_LINUX if (FLAG_perf_basic_prof) { @@ -2063,9 +2059,7 @@ bool Logger::SetUp(Isolate* isolate) { ticker_ = std::make_unique(isolate, FLAG_prof_sampling_interval); - if (Log::InitLogAtStart()) { - is_logging_ = true; - } + if (Log::InitLogAtStart()) is_logging_ = true; timer_.Start(); @@ -2075,9 +2069,7 @@ bool Logger::SetUp(Isolate* isolate) { profiler_->Engage(); } - if (is_logging_) { - AddCodeEventListener(this); - } + if (is_logging_) AddCodeEventListener(this); return true; } @@ -2104,6 +2096,7 @@ void Logger::SetCodeEventHandler(uint32_t options, } sampler::Sampler* Logger::sampler() { return ticker_.get(); } +std::string Logger::file_name() const { return log_.get()->file_name(); } void Logger::StopProfilerThread() { if (profiler_ != nullptr) { @@ -2112,14 +2105,16 @@ void Logger::StopProfilerThread() { } } -FILE* Logger::TearDown() { +FILE* Logger::TearDownAndGetLogFile() { if (!is_initialized_) return nullptr; is_initialized_ = false; + is_logging_ = false; // Stop the profiler thread before closing the file. StopProfilerThread(); ticker_.reset(); + timer_.Stop(); #if V8_OS_LINUX if (perf_basic_logger_) { diff --git a/src/logging/log.h b/src/logging/log.h index c5c4217d0a..ff9a717766 100644 --- a/src/logging/log.h +++ b/src/logging/log.h @@ -126,18 +126,19 @@ class Logger : public CodeEventListener { // Acquires resources for logging if the right flags are set. bool SetUp(Isolate* isolate); + // Frees resources acquired in SetUp. + // When a temporary file is used for the log, returns its stream descriptor, + // leaving the file open. + V8_EXPORT_PRIVATE FILE* TearDownAndGetLogFile(); + // Sets the current code event handler. void SetCodeEventHandler(uint32_t options, JitCodeEventHandler event_handler); sampler::Sampler* sampler(); + V8_EXPORT_PRIVATE std::string file_name() const; V8_EXPORT_PRIVATE void StopProfilerThread(); - // Frees resources acquired in SetUp. - // When a temporary file is used for the log, returns its stream descriptor, - // leaving the file open. - V8_EXPORT_PRIVATE FILE* TearDown(); - // Emits an event with a string value -> (name, value). V8_EXPORT_PRIVATE void StringEvent(const char* name, const char* value); diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc index 2daa69103a..ad2fe819ad 100644 --- a/test/cctest/test-log.cc +++ b/test/cctest/test-log.cc @@ -83,8 +83,8 @@ class ScopedLoggerInitializer { ~ScopedLoggerInitializer() { env_->Exit(); - logger_->TearDown(); - if (temp_file_ != nullptr) fclose(temp_file_); + FILE* log_file = logger_->TearDownAndGetLogFile(); + if (log_file != nullptr) fclose(log_file); i::FLAG_prof = saved_prof_; i::FLAG_log = saved_log_; } @@ -203,9 +203,8 @@ class ScopedLoggerInitializer { private: FILE* StopLoggingGetTempFile() { - temp_file_ = logger_->TearDown(); + temp_file_ = logger_->TearDownAndGetLogFile(); CHECK(temp_file_); - fflush(temp_file_); rewind(temp_file_); return temp_file_; } diff --git a/test/mjsunit/tools/log.js b/test/mjsunit/tools/log.js new file mode 100644 index 0000000000..bea27e7e85 --- /dev/null +++ b/test/mjsunit/tools/log.js @@ -0,0 +1,25 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --log-all --log --no-stress-opt + +function testFunctionWithFunnyName(o) { + return o.a; +} + +(function testLoopWithFunnyName() { + const o = {a:1}; + let result = 0; + for (let i = 0; i < 1000; i++) { + result += testFunctionWithFunnyName(o); + } +})(); + +const log = d8.log.getAndStop(); + +// Check that we have a minimally working log file. +assertTrue(log.length > 0); +assertTrue(log.indexOf('v8-version') == 0); +assertTrue(log.indexOf('testFunctionWithFunnyName') >= 10); +assertTrue(log.indexOf('testLoopWithFunnyName') >= 10);