LCOV - code coverage report
Current view: top level - test/cctest - test-log.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 164 187 87.7 %
Date: 2017-10-20 Functions: 20 30 66.7 %

          Line data    Source code
       1             : // Copyright 2006-2009 the V8 project authors. All rights reserved.
       2             : // Redistribution and use in source and binary forms, with or without
       3             : // modification, are permitted provided that the following conditions are
       4             : // met:
       5             : //
       6             : //     * Redistributions of source code must retain the above copyright
       7             : //       notice, this list of conditions and the following disclaimer.
       8             : //     * Redistributions in binary form must reproduce the above
       9             : //       copyright notice, this list of conditions and the following
      10             : //       disclaimer in the documentation and/or other materials provided
      11             : //       with the distribution.
      12             : //     * Neither the name of Google Inc. nor the names of its
      13             : //       contributors may be used to endorse or promote products derived
      14             : //       from this software without specific prior written permission.
      15             : //
      16             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      17             : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      18             : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      19             : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      20             : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      21             : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      22             : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23             : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25             : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      26             : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             : //
      28             : // Tests of logging functions from log.h
      29             : 
      30             : #ifdef __linux__
      31             : #include <pthread.h>
      32             : #include <signal.h>
      33             : #include <unistd.h>
      34             : #include <cmath>
      35             : #endif  // __linux__
      36             : 
      37             : #include "src/api.h"
      38             : #include "src/log-utils.h"
      39             : #include "src/log.h"
      40             : #include "src/objects-inl.h"
      41             : #include "src/profiler/cpu-profiler.h"
      42             : #include "src/snapshot/natives.h"
      43             : #include "src/utils.h"
      44             : #include "src/v8.h"
      45             : #include "src/v8threads.h"
      46             : #include "src/version.h"
      47             : #include "src/vm-state-inl.h"
      48             : #include "test/cctest/cctest.h"
      49             : 
      50             : using v8::internal::Address;
      51             : using v8::internal::EmbeddedVector;
      52             : using v8::internal::Logger;
      53             : using v8::internal::StrLength;
      54             : 
      55             : namespace {
      56             : 
      57             : 
      58             : #define SETUP_FLAGS()                            \
      59             :   bool saved_log = i::FLAG_log;                  \
      60             :   bool saved_prof = i::FLAG_prof;                \
      61             :   i::FLAG_log = true;                            \
      62             :   i::FLAG_prof = true;                           \
      63             :   i::FLAG_logfile = i::Log::kLogToTemporaryFile; \
      64             :   i::FLAG_logfile_per_isolate = false
      65             : 
      66        6895 : static const char* StrNStr(const char* s1, const char* s2, size_t n) {
      67        6895 :   CHECK_EQ(s1[n], '\0');
      68        6895 :   return strstr(s1, s2);
      69             : }
      70             : 
      71             : // Look for a log line which starts with {prefix} and ends with {suffix}.
      72          70 : static const char* FindLogLine(i::Vector<const char>* log, const char* prefix,
      73             :                                const char* suffix) {
      74             :   const char* start = log->start();
      75          70 :   const char* end = start + log->length();
      76          70 :   CHECK_EQ(end[0], '\0');
      77          70 :   size_t prefixLength = strlen(prefix);
      78             :   // Loop through the input until we find /{prefix}[^\n]+{suffix}/.
      79        2385 :   while (start < end) {
      80        2315 :     const char* prefixResult = StrNStr(start, prefix, (end - start));
      81        2315 :     if (!prefixResult) return NULL;
      82             :     const char* suffixResult =
      83        2295 :         StrNStr(prefixResult, suffix, (end - prefixResult));
      84        2295 :     if (!suffixResult) return NULL;
      85             :     // Check that there are no newlines in between the {prefix} and the {suffix}
      86             :     // results.
      87             :     const char* newlineResult =
      88        2285 :         StrNStr(prefixResult, "\n", (end - prefixResult));
      89        2285 :     if (!newlineResult) return prefixResult;
      90        2280 :     if (newlineResult > suffixResult) return prefixResult;
      91        2245 :     start = prefixResult + prefixLength;
      92             :   }
      93             :   return NULL;
      94             : }
      95             : 
      96             : class ScopedLoggerInitializer {
      97             :  public:
      98          42 :   ScopedLoggerInitializer(bool saved_log, bool saved_prof, v8::Isolate* isolate)
      99             :       : saved_log_(saved_log),
     100             :         saved_prof_(saved_prof),
     101             :         temp_file_(nullptr),
     102             :         isolate_(isolate),
     103             :         isolate_scope_(isolate),
     104             :         scope_(isolate),
     105          21 :         env_(v8::Context::New(isolate)),
     106          84 :         logger_(reinterpret_cast<i::Isolate*>(isolate)->logger()) {
     107          21 :     env_->Enter();
     108          21 :   }
     109             : 
     110          42 :   ~ScopedLoggerInitializer() {
     111          21 :     env_->Exit();
     112          21 :     logger_->TearDown();
     113          21 :     if (temp_file_ != nullptr) fclose(temp_file_);
     114          21 :     i::FLAG_prof = saved_prof_;
     115          21 :     i::FLAG_log = saved_log_;
     116             :     log_.Dispose();
     117          21 :   }
     118             : 
     119             :   v8::Local<v8::Context>& env() { return env_; }
     120             : 
     121             :   v8::Isolate* isolate() { return isolate_; }
     122             : 
     123             :   Logger* logger() { return logger_; }
     124             : 
     125           1 :   v8::Local<v8::String> GetLogString() {
     126             :     return v8::String::NewFromUtf8(isolate_, log_.start(),
     127           2 :                                    v8::NewStringType::kNormal, log_.length())
     128           2 :         .ToLocalChecked();
     129             :   }
     130             : 
     131          32 :   void StopLogging() {
     132          16 :     bool exists = false;
     133          16 :     log_ = i::ReadFile(StopLoggingGetTempFile(), &exists, true);
     134          16 :     CHECK(exists);
     135          16 :   }
     136             : 
     137             :   const char* FindLine(const char* prefix, const char* suffix) {
     138          25 :     return FindLogLine(&log_, prefix, suffix);
     139             :   }
     140             : 
     141          11 :   void LogCompiledFunctions() { logger_->LogCompiledFunctions(); }
     142             : 
     143             :   void StringEvent(const char* name, const char* value) {
     144           2 :     logger_->StringEvent(name, value);
     145             :   }
     146             : 
     147             :  private:
     148          16 :   FILE* StopLoggingGetTempFile() {
     149          16 :     temp_file_ = logger_->TearDown();
     150          16 :     CHECK(temp_file_);
     151          16 :     fflush(temp_file_);
     152          16 :     rewind(temp_file_);
     153          16 :     return temp_file_;
     154             :   }
     155             : 
     156             :   const bool saved_log_;
     157             :   const bool saved_prof_;
     158             :   FILE* temp_file_;
     159             :   v8::Isolate* isolate_;
     160             :   v8::Isolate::Scope isolate_scope_;
     161             :   v8::HandleScope scope_;
     162             :   v8::Local<v8::Context> env_;
     163             :   Logger* logger_;
     164             :   i::Vector<const char> log_;
     165             : 
     166             :   DISALLOW_COPY_AND_ASSIGN(ScopedLoggerInitializer);
     167             : };
     168             : 
     169             : }  // namespace
     170             : 
     171       23723 : TEST(FindLogLine) {
     172             :   const char* string =
     173             :       "prefix1, stuff,   suffix1\n"
     174             :       "prefix2, stuff\n, suffix2\n"
     175             :       "prefix3suffix3\n"
     176             :       "prefix4 suffix4";
     177             :   // Make sure the vector contains the terminating \0 character.
     178             :   i::Vector<const char> log(string, strlen(string));
     179           5 :   CHECK(FindLogLine(&log, "prefix1", "suffix1"));
     180           5 :   CHECK(FindLogLine(&log, "prefix1", "suffix1"));
     181           5 :   CHECK(!FindLogLine(&log, "prefix2", "suffix2"));
     182           5 :   CHECK(!FindLogLine(&log, "prefix1", "suffix2"));
     183           5 :   CHECK(!FindLogLine(&log, "prefix1", "suffix3"));
     184           5 :   CHECK(FindLogLine(&log, "prefix3", "suffix3"));
     185           5 :   CHECK(FindLogLine(&log, "prefix4", "suffix4"));
     186           5 :   CHECK(!FindLogLine(&log, "prefix4", "suffix4XXXXXXXXXXXX"));
     187           5 :   CHECK(!FindLogLine(&log, "prefix4XXXXXXXXXXXXXXXXXXXXXXxxx", "suffix4"));
     188           5 :   CHECK(!FindLogLine(&log, "suffix", "suffix5XXXXXXXXXXXXXXXXXXXX"));
     189           5 : }
     190             : 
     191             : // BUG(913). Need to implement support for profiling multiple VM threads.
     192             : #if 0
     193             : 
     194             : namespace {
     195             : 
     196             : class LoopingThread : public v8::internal::Thread {
     197             :  public:
     198             :   explicit LoopingThread(v8::internal::Isolate* isolate)
     199             :       : v8::internal::Thread(isolate),
     200             :         semaphore_(new v8::internal::Semaphore(0)),
     201             :         run_(true) {
     202             :   }
     203             : 
     204             :   virtual ~LoopingThread() { delete semaphore_; }
     205             : 
     206             :   void Run() {
     207             :     self_ = pthread_self();
     208             :     RunLoop();
     209             :   }
     210             : 
     211             :   void SendSigProf() { pthread_kill(self_, SIGPROF); }
     212             : 
     213             :   void Stop() { run_ = false; }
     214             : 
     215             :   bool WaitForRunning() { return semaphore_->Wait(1000000); }
     216             : 
     217             :  protected:
     218             :   bool IsRunning() { return run_; }
     219             : 
     220             :   virtual void RunLoop() = 0;
     221             : 
     222             :   void SetV8ThreadId() {
     223             :     v8_thread_id_ = v8::V8::GetCurrentThreadId();
     224             :   }
     225             : 
     226             :   void SignalRunning() { semaphore_->Signal(); }
     227             : 
     228             :  private:
     229             :   v8::internal::Semaphore* semaphore_;
     230             :   bool run_;
     231             :   pthread_t self_;
     232             :   int v8_thread_id_;
     233             : };
     234             : 
     235             : 
     236             : class LoopingJsThread : public LoopingThread {
     237             :  public:
     238             :   explicit LoopingJsThread(v8::internal::Isolate* isolate)
     239             :       : LoopingThread(isolate) { }
     240             :   void RunLoop() {
     241             :     v8::Locker locker;
     242             :     CHECK_NOT_NULL(CcTest::i_isolate());
     243             :     CHECK_GT(CcTest::i_isolate()->thread_manager()->CurrentId(), 0);
     244             :     SetV8ThreadId();
     245             :     while (IsRunning()) {
     246             :       v8::HandleScope scope;
     247             :       v8::Persistent<v8::Context> context = v8::Context::New();
     248             :       CHECK(!context.IsEmpty());
     249             :       {
     250             :         v8::Context::Scope context_scope(context);
     251             :         SignalRunning();
     252             :         CompileRun(
     253             :             "var j; for (var i=0; i<10000; ++i) { j = Math.sin(i); }");
     254             :       }
     255             :       context.Dispose();
     256             :       i::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(1));
     257             :     }
     258             :   }
     259             : };
     260             : 
     261             : 
     262             : class LoopingNonJsThread : public LoopingThread {
     263             :  public:
     264             :   explicit LoopingNonJsThread(v8::internal::Isolate* isolate)
     265             :       : LoopingThread(isolate) { }
     266             :   void RunLoop() {
     267             :     v8::Locker locker;
     268             :     v8::Unlocker unlocker;
     269             :     // Now thread has V8's id, but will not run VM code.
     270             :     CHECK_NOT_NULL(CcTest::i_isolate());
     271             :     CHECK_GT(CcTest::i_isolate()->thread_manager()->CurrentId(), 0);
     272             :     double i = 10;
     273             :     SignalRunning();
     274             :     while (IsRunning()) {
     275             :       i = std::sin(i);
     276             :       i::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(1));
     277             :     }
     278             :   }
     279             : };
     280             : 
     281             : 
     282             : class TestSampler : public v8::internal::Sampler {
     283             :  public:
     284             :   explicit TestSampler(v8::internal::Isolate* isolate)
     285             :       : Sampler(isolate, 0, true, true),
     286             :         semaphore_(new v8::internal::Semaphore(0)),
     287             :         was_sample_stack_called_(false) {
     288             :   }
     289             : 
     290             :   ~TestSampler() { delete semaphore_; }
     291             : 
     292             :   void SampleStack(v8::internal::TickSample*) {
     293             :     was_sample_stack_called_ = true;
     294             :   }
     295             : 
     296             :   void Tick(v8::internal::TickSample*) { semaphore_->Signal(); }
     297             : 
     298             :   bool WaitForTick() { return semaphore_->Wait(1000000); }
     299             : 
     300             :   void Reset() { was_sample_stack_called_ = false; }
     301             : 
     302             :   bool WasSampleStackCalled() { return was_sample_stack_called_; }
     303             : 
     304             :  private:
     305             :   v8::internal::Semaphore* semaphore_;
     306             :   bool was_sample_stack_called_;
     307             : };
     308             : 
     309             : 
     310             : }  // namespace
     311             : 
     312             : TEST(ProfMultipleThreads) {
     313             :   TestSampler* sampler = nullptr;
     314             :   {
     315             :     v8::Locker locker;
     316             :     sampler = new TestSampler(CcTest::i_isolate());
     317             :     sampler->Start();
     318             :     CHECK(sampler->IsActive());
     319             :   }
     320             : 
     321             :   LoopingJsThread jsThread(CcTest::i_isolate());
     322             :   jsThread.Start();
     323             :   LoopingNonJsThread nonJsThread(CcTest::i_isolate());
     324             :   nonJsThread.Start();
     325             : 
     326             :   CHECK(!sampler->WasSampleStackCalled());
     327             :   jsThread.WaitForRunning();
     328             :   jsThread.SendSigProf();
     329             :   CHECK(sampler->WaitForTick());
     330             :   CHECK(sampler->WasSampleStackCalled());
     331             :   sampler->Reset();
     332             :   CHECK(!sampler->WasSampleStackCalled());
     333             :   nonJsThread.WaitForRunning();
     334             :   nonJsThread.SendSigProf();
     335             :   CHECK(!sampler->WaitForTick());
     336             :   CHECK(!sampler->WasSampleStackCalled());
     337             :   sampler->Stop();
     338             : 
     339             :   jsThread.Stop();
     340             :   nonJsThread.Stop();
     341             :   jsThread.Join();
     342             :   nonJsThread.Join();
     343             : 
     344             :   delete sampler;
     345             : }
     346             : 
     347             : #endif  // __linux__
     348             : 
     349             : 
     350             : // Test for issue http://crbug.com/23768 in Chromium.
     351             : // Heap can contain scripts with already disposed external sources.
     352             : // We need to verify that LogCompiledFunctions doesn't crash on them.
     353             : namespace {
     354             : 
     355             : class SimpleExternalString : public v8::String::ExternalStringResource {
     356             :  public:
     357           5 :   explicit SimpleExternalString(const char* source)
     358           5 :       : utf_source_(StrLength(source)) {
     359         230 :     for (int i = 0; i < utf_source_.length(); ++i)
     360         335 :       utf_source_[i] = source[i];
     361           5 :   }
     362           5 :   virtual ~SimpleExternalString() {}
     363          30 :   virtual size_t length() const { return utf_source_.length(); }
     364          25 :   virtual const uint16_t* data() const { return utf_source_.start(); }
     365             :  private:
     366             :   i::ScopedVector<uint16_t> utf_source_;
     367             : };
     368             : 
     369             : }  // namespace
     370             : 
     371       23723 : TEST(Issue23768) {
     372           5 :   v8::HandleScope scope(CcTest::isolate());
     373           5 :   v8::Local<v8::Context> env = v8::Context::New(CcTest::isolate());
     374           5 :   env->Enter();
     375             : 
     376           5 :   SimpleExternalString source_ext_str("(function ext() {})();");
     377             :   v8::Local<v8::String> source =
     378           5 :       v8::String::NewExternalTwoByte(CcTest::isolate(), &source_ext_str)
     379           5 :           .ToLocalChecked();
     380             :   // Script needs to have a name in order to trigger InitLineEnds execution.
     381             :   v8::Local<v8::String> origin =
     382             :       v8::String::NewFromUtf8(CcTest::isolate(), "issue-23768-test",
     383           5 :                               v8::NewStringType::kNormal)
     384          10 :           .ToLocalChecked();
     385           5 :   v8::Local<v8::Script> evil_script = CompileWithOrigin(source, origin);
     386           5 :   CHECK(!evil_script.IsEmpty());
     387          10 :   CHECK(!evil_script->Run(env).IsEmpty());
     388             :   i::Handle<i::ExternalTwoByteString> i_source(
     389             :       i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
     390             :   // This situation can happen if source was an external string disposed
     391             :   // by its owner.
     392             :   i_source->set_resource(nullptr);
     393             : 
     394             :   // Must not crash.
     395          10 :   CcTest::i_isolate()->logger()->LogCompiledFunctions();
     396           5 : }
     397             : 
     398             : 
     399           0 : static void ObjMethod1(const v8::FunctionCallbackInfo<v8::Value>& args) {
     400           0 : }
     401             : 
     402             : 
     403       23723 : TEST(LogCallbacks) {
     404           5 :   SETUP_FLAGS();
     405             :   v8::Isolate::CreateParams create_params;
     406           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     407           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     408             :   {
     409           5 :     ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
     410             : 
     411             :     v8::Local<v8::FunctionTemplate> obj = v8::Local<v8::FunctionTemplate>::New(
     412          10 :         isolate, v8::FunctionTemplate::New(isolate));
     413           5 :     obj->SetClassName(v8_str("Obj"));
     414           5 :     v8::Local<v8::ObjectTemplate> proto = obj->PrototypeTemplate();
     415           5 :     v8::Local<v8::Signature> signature = v8::Signature::New(isolate, obj);
     416             :     proto->Set(v8_str("method1"),
     417             :                v8::FunctionTemplate::New(isolate, ObjMethod1,
     418             :                                          v8::Local<v8::Value>(), signature),
     419          15 :                static_cast<v8::PropertyAttribute>(v8::DontDelete));
     420             : 
     421             :     logger.env()
     422             :         ->Global()
     423             :         ->Set(logger.env(), v8_str("Obj"),
     424          20 :               obj->GetFunction(logger.env()).ToLocalChecked())
     425          10 :         .FromJust();
     426             :     CompileRun("Obj.prototype.method1.toString();");
     427             : 
     428           5 :     logger.LogCompiledFunctions();
     429             : 
     430           5 :     logger.StopLogging();
     431             : 
     432             :     Address ObjMethod1_entry = reinterpret_cast<Address>(ObjMethod1);
     433             : #if USES_FUNCTION_DESCRIPTORS
     434             :     ObjMethod1_entry = *FUNCTION_ENTRYPOINT_ADDRESS(ObjMethod1_entry);
     435             : #endif
     436             :     i::EmbeddedVector<char, 100> ref_data;
     437             :     i::SNPrintF(ref_data, ",0x%" V8PRIxPTR ",1,\"method1\"",
     438           5 :                 reinterpret_cast<intptr_t>(ObjMethod1_entry));
     439          10 :     CHECK(logger.FindLine("code-creation,Callback,-2,", ref_data.start()));
     440             :   }
     441           5 :   isolate->Dispose();
     442           5 : }
     443             : 
     444             : 
     445           0 : static void Prop1Getter(v8::Local<v8::String> property,
     446             :                         const v8::PropertyCallbackInfo<v8::Value>& info) {
     447           0 : }
     448             : 
     449           0 : static void Prop1Setter(v8::Local<v8::String> property,
     450             :                         v8::Local<v8::Value> value,
     451             :                         const v8::PropertyCallbackInfo<void>& info) {
     452           0 : }
     453             : 
     454           0 : static void Prop2Getter(v8::Local<v8::String> property,
     455             :                         const v8::PropertyCallbackInfo<v8::Value>& info) {
     456           0 : }
     457             : 
     458             : 
     459       23723 : TEST(LogAccessorCallbacks) {
     460           5 :   SETUP_FLAGS();
     461             :   v8::Isolate::CreateParams create_params;
     462           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     463           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     464             :   {
     465           5 :     ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
     466             : 
     467             :     v8::Local<v8::FunctionTemplate> obj = v8::Local<v8::FunctionTemplate>::New(
     468          10 :         isolate, v8::FunctionTemplate::New(isolate));
     469           5 :     obj->SetClassName(v8_str("Obj"));
     470           5 :     v8::Local<v8::ObjectTemplate> inst = obj->InstanceTemplate();
     471           5 :     inst->SetAccessor(v8_str("prop1"), Prop1Getter, Prop1Setter);
     472           5 :     inst->SetAccessor(v8_str("prop2"), Prop2Getter);
     473             : 
     474           5 :     logger.logger()->LogAccessorCallbacks();
     475             : 
     476           5 :     logger.StopLogging();
     477             : 
     478             :     Address Prop1Getter_entry = reinterpret_cast<Address>(Prop1Getter);
     479             : #if USES_FUNCTION_DESCRIPTORS
     480             :     Prop1Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Getter_entry);
     481             : #endif
     482             :     EmbeddedVector<char, 100> prop1_getter_record;
     483             :     i::SNPrintF(prop1_getter_record, ",0x%" V8PRIxPTR ",1,\"get prop1\"",
     484           5 :                 reinterpret_cast<intptr_t>(Prop1Getter_entry));
     485          10 :     CHECK(logger.FindLine("code-creation,Callback,-2,",
     486             :                           prop1_getter_record.start()));
     487             : 
     488             :     Address Prop1Setter_entry = reinterpret_cast<Address>(Prop1Setter);
     489             : #if USES_FUNCTION_DESCRIPTORS
     490             :     Prop1Setter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Setter_entry);
     491             : #endif
     492             :     EmbeddedVector<char, 100> prop1_setter_record;
     493             :     i::SNPrintF(prop1_setter_record, ",0x%" V8PRIxPTR ",1,\"set prop1\"",
     494           5 :                 reinterpret_cast<intptr_t>(Prop1Setter_entry));
     495          10 :     CHECK(logger.FindLine("code-creation,Callback,-2,",
     496             :                           prop1_setter_record.start()));
     497             : 
     498             :     Address Prop2Getter_entry = reinterpret_cast<Address>(Prop2Getter);
     499             : #if USES_FUNCTION_DESCRIPTORS
     500             :     Prop2Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop2Getter_entry);
     501             : #endif
     502             :     EmbeddedVector<char, 100> prop2_getter_record;
     503             :     i::SNPrintF(prop2_getter_record, ",0x%" V8PRIxPTR ",1,\"get prop2\"",
     504           5 :                 reinterpret_cast<intptr_t>(Prop2Getter_entry));
     505          10 :     CHECK(logger.FindLine("code-creation,Callback,-2,",
     506           5 :                           prop2_getter_record.start()));
     507             :   }
     508           5 :   isolate->Dispose();
     509           5 : }
     510             : 
     511             : // Test that logging of code create / move events is equivalent to traversal of
     512             : // a resulting heap.
     513       23719 : TEST(EquivalenceOfLoggingAndTraversal) {
     514             :   // This test needs to be run on a "clean" V8 to ensure that snapshot log
     515             :   // is loaded. This is always true when running using tools/test.py because
     516             :   // it launches a new cctest instance for every test. To be sure that launching
     517             :   // cctest manually also works, please be sure that no tests below
     518             :   // are using V8.
     519             : 
     520             :   // Start with profiling to capture all code events from the beginning.
     521           1 :   SETUP_FLAGS();
     522             :   v8::Isolate::CreateParams create_params;
     523           1 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     524           1 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     525             :   {
     526           1 :     ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
     527             : 
     528             :     // Compile and run a function that creates other functions.
     529             :     CompileRun(
     530             :         "(function f(obj) {\n"
     531             :         "  obj.test =\n"
     532             :         "    (function a(j) { return function b() { return j; } })(100);\n"
     533             :         "})(this);");
     534           1 :     logger.logger()->StopProfiler();
     535             :     reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage(
     536           1 :         i::Heap::kMakeHeapIterableMask, i::GarbageCollectionReason::kTesting);
     537           1 :     logger.StringEvent("test-logging-done", "");
     538             : 
     539             :     // Iterate heap to find compiled functions, will write to log.
     540           1 :     logger.LogCompiledFunctions();
     541           1 :     logger.StringEvent("test-traversal-done", "");
     542             : 
     543           1 :     logger.StopLogging();
     544             : 
     545           1 :     v8::Local<v8::String> log_str = logger.GetLogString();
     546             :     logger.env()
     547             :         ->Global()
     548           3 :         ->Set(logger.env(), v8_str("_log"), log_str)
     549           2 :         .FromJust();
     550             : 
     551             :     // Load the Test snapshot's sources, see log-eq-of-logging-and-traversal.js
     552             :     i::Vector<const char> source =
     553           1 :         i::NativesCollection<i::TEST>::GetScriptsSource();
     554             :     v8::Local<v8::String> source_str =
     555             :         v8::String::NewFromUtf8(isolate, source.start(),
     556           2 :                                 v8::NewStringType::kNormal, source.length())
     557           1 :             .ToLocalChecked();
     558           2 :     v8::TryCatch try_catch(isolate);
     559             :     v8::Local<v8::Script> script = CompileWithOrigin(source_str, "");
     560           1 :     if (script.IsEmpty()) {
     561           0 :       v8::String::Utf8Value exception(isolate, try_catch.Exception());
     562           0 :       printf("compile: %s\n", *exception);
     563           0 :       CHECK(false);
     564             :     }
     565             :     v8::Local<v8::Value> result;
     566           2 :     if (!script->Run(logger.env()).ToLocal(&result)) {
     567           0 :       v8::String::Utf8Value exception(isolate, try_catch.Exception());
     568           0 :       printf("run: %s\n", *exception);
     569           0 :       CHECK(false);
     570             :     }
     571             :     // The result either be the "true" literal or problem description.
     572           1 :     if (!result->IsTrue()) {
     573           0 :       v8::Local<v8::String> s = result->ToString(logger.env()).ToLocalChecked();
     574           0 :       i::ScopedVector<char> data(s->Utf8Length() + 1);
     575           0 :       CHECK(data.start());
     576           0 :       s->WriteUtf8(data.start());
     577             :       printf("%s\n", data.start());
     578             :       // Make sure that our output is written prior crash due to CHECK failure.
     579           0 :       fflush(stdout);
     580           0 :       CHECK(false);
     581           1 :     }
     582             :   }
     583           1 :   isolate->Dispose();
     584           1 : }
     585             : 
     586             : 
     587       23723 : TEST(LogVersion) {
     588           5 :   SETUP_FLAGS();
     589             :   v8::Isolate::CreateParams create_params;
     590           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     591           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     592             :   {
     593           5 :     ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
     594           5 :     logger.StopLogging();
     595             : 
     596             :     i::EmbeddedVector<char, 100> ref_data;
     597             :     i::SNPrintF(ref_data, "%d,%d,%d,%d,%d", i::Version::GetMajor(),
     598             :                 i::Version::GetMinor(), i::Version::GetBuild(),
     599          10 :                 i::Version::GetPatch(), i::Version::IsCandidate());
     600          10 :     CHECK(logger.FindLine("v8-version,", ref_data.start()));
     601             :   }
     602           5 :   isolate->Dispose();
     603           5 : }
     604             : 
     605             : 
     606             : // https://crbug.com/539892
     607             : // CodeCreateEvents with really large names should not crash.
     608       23723 : TEST(Issue539892) {
     609          10 :   class : public i::CodeEventLogger {
     610             :    public:
     611           0 :     void CodeMoveEvent(i::AbstractCode* from, Address to) override {}
     612           0 :     void CodeDisableOptEvent(i::AbstractCode* code,
     613           0 :                              i::SharedFunctionInfo* shared) override {}
     614             : 
     615             :    private:
     616        2630 :     void LogRecordedBuffer(i::AbstractCode* code, i::SharedFunctionInfo* shared,
     617        2630 :                            const char* name, int length) override {}
     618             :   } code_event_logger;
     619           5 :   SETUP_FLAGS();
     620             :   v8::Isolate::CreateParams create_params;
     621           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     622           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     623             : 
     624             :   {
     625           5 :     ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
     626           5 :     logger.logger()->addCodeEventListener(&code_event_logger);
     627             : 
     628             :     // Function with a really large name.
     629             :     const char* source_text =
     630             :         "(function "
     631             :         "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     632             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     633             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     634             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     635             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     636             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     637             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     638             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     639             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     640             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     641             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     642             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     643             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     644             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     645             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     646             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
     647             :         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac"
     648             :         "(){})();";
     649             : 
     650             :     CompileRun(source_text);
     651             : 
     652             :     // Must not crash.
     653          10 :     logger.LogCompiledFunctions();
     654             :   }
     655           5 :   isolate->Dispose();
     656       71159 : }

Generated by: LCOV version 1.10