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/v8.h" 38 39 #include "src/log.h" 40 #include "src/log-utils.h" 41 #include "src/profiler/cpu-profiler.h" 42 #include "src/snapshot/natives.h" 43 #include "src/utils.h" 44 #include "src/v8threads.h" 45 #include "src/version.h" 46 #include "src/vm-state-inl.h" 47 #include "test/cctest/cctest.h" 48 49 using v8::internal::Address; 50 using v8::internal::EmbeddedVector; 51 using v8::internal::Logger; 52 using v8::internal::StrLength; 53 54 namespace { 55 56 57 #define SETUP_FLAGS() \ 58 bool saved_log = i::FLAG_log; \ 59 bool saved_prof = i::FLAG_prof; \ 60 i::FLAG_log = true; \ 61 i::FLAG_prof = true; \ 62 i::FLAG_logfile = i::Log::kLogToTemporaryFile; \ 63 i::FLAG_logfile_per_isolate = false 64 65 66 class ScopedLoggerInitializer { 67 public: 68 ScopedLoggerInitializer(bool saved_log, bool saved_prof, v8::Isolate* isolate) 69 : saved_log_(saved_log), 70 saved_prof_(saved_prof), 71 temp_file_(NULL), 72 isolate_(isolate), 73 isolate_scope_(isolate), 74 scope_(isolate), 75 env_(v8::Context::New(isolate)), 76 logger_(reinterpret_cast<i::Isolate*>(isolate)->logger()) { 77 env_->Enter(); 78 } 79 80 ~ScopedLoggerInitializer() { 81 env_->Exit(); 82 logger_->TearDown(); 83 if (temp_file_ != NULL) fclose(temp_file_); 84 i::FLAG_prof = saved_prof_; 85 i::FLAG_log = saved_log_; 86 } 87 88 v8::Local<v8::Context>& env() { return env_; } 89 90 v8::Isolate* isolate() { return isolate_; } 91 92 Logger* logger() { return logger_; } 93 94 FILE* StopLoggingGetTempFile() { 95 temp_file_ = logger_->TearDown(); 96 CHECK(temp_file_); 97 fflush(temp_file_); 98 rewind(temp_file_); 99 return temp_file_; 100 } 101 102 private: 103 const bool saved_log_; 104 const bool saved_prof_; 105 FILE* temp_file_; 106 v8::Isolate* isolate_; 107 v8::Isolate::Scope isolate_scope_; 108 v8::HandleScope scope_; 109 v8::Local<v8::Context> env_; 110 Logger* logger_; 111 112 DISALLOW_COPY_AND_ASSIGN(ScopedLoggerInitializer); 113 }; 114 115 } // namespace 116 117 118 static const char* StrNStr(const char* s1, const char* s2, int n) { 119 if (s1[n] == '\0') return strstr(s1, s2); 120 i::ScopedVector<char> str(n + 1); 121 i::StrNCpy(str, s1, static_cast<size_t>(n)); 122 str[n] = '\0'; 123 char* found = strstr(str.start(), s2); 124 return found != NULL ? s1 + (found - str.start()) : NULL; 125 } 126 127 128 // BUG(913). Need to implement support for profiling multiple VM threads. 129 #if 0 130 131 namespace { 132 133 class LoopingThread : public v8::internal::Thread { 134 public: 135 explicit LoopingThread(v8::internal::Isolate* isolate) 136 : v8::internal::Thread(isolate), 137 semaphore_(new v8::internal::Semaphore(0)), 138 run_(true) { 139 } 140 141 virtual ~LoopingThread() { delete semaphore_; } 142 143 void Run() { 144 self_ = pthread_self(); 145 RunLoop(); 146 } 147 148 void SendSigProf() { pthread_kill(self_, SIGPROF); } 149 150 void Stop() { run_ = false; } 151 152 bool WaitForRunning() { return semaphore_->Wait(1000000); } 153 154 protected: 155 bool IsRunning() { return run_; } 156 157 virtual void RunLoop() = 0; 158 159 void SetV8ThreadId() { 160 v8_thread_id_ = v8::V8::GetCurrentThreadId(); 161 } 162 163 void SignalRunning() { semaphore_->Signal(); } 164 165 private: 166 v8::internal::Semaphore* semaphore_; 167 bool run_; 168 pthread_t self_; 169 int v8_thread_id_; 170 }; 171 172 173 class LoopingJsThread : public LoopingThread { 174 public: 175 explicit LoopingJsThread(v8::internal::Isolate* isolate) 176 : LoopingThread(isolate) { } 177 void RunLoop() { 178 v8::Locker locker; 179 CHECK(CcTest::i_isolate() != NULL); 180 CHECK_GT(CcTest::i_isolate()->thread_manager()->CurrentId(), 0); 181 SetV8ThreadId(); 182 while (IsRunning()) { 183 v8::HandleScope scope; 184 v8::Persistent<v8::Context> context = v8::Context::New(); 185 CHECK(!context.IsEmpty()); 186 { 187 v8::Context::Scope context_scope(context); 188 SignalRunning(); 189 CompileRun( 190 "var j; for (var i=0; i<10000; ++i) { j = Math.sin(i); }"); 191 } 192 context.Dispose(); 193 i::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(1)); 194 } 195 } 196 }; 197 198 199 class LoopingNonJsThread : public LoopingThread { 200 public: 201 explicit LoopingNonJsThread(v8::internal::Isolate* isolate) 202 : LoopingThread(isolate) { } 203 void RunLoop() { 204 v8::Locker locker; 205 v8::Unlocker unlocker; 206 // Now thread has V8's id, but will not run VM code. 207 CHECK(CcTest::i_isolate() != NULL); 208 CHECK_GT(CcTest::i_isolate()->thread_manager()->CurrentId(), 0); 209 double i = 10; 210 SignalRunning(); 211 while (IsRunning()) { 212 i = std::sin(i); 213 i::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(1)); 214 } 215 } 216 }; 217 218 219 class TestSampler : public v8::internal::Sampler { 220 public: 221 explicit TestSampler(v8::internal::Isolate* isolate) 222 : Sampler(isolate, 0, true, true), 223 semaphore_(new v8::internal::Semaphore(0)), 224 was_sample_stack_called_(false) { 225 } 226 227 ~TestSampler() { delete semaphore_; } 228 229 void SampleStack(v8::internal::TickSample*) { 230 was_sample_stack_called_ = true; 231 } 232 233 void Tick(v8::internal::TickSample*) { semaphore_->Signal(); } 234 235 bool WaitForTick() { return semaphore_->Wait(1000000); } 236 237 void Reset() { was_sample_stack_called_ = false; } 238 239 bool WasSampleStackCalled() { return was_sample_stack_called_; } 240 241 private: 242 v8::internal::Semaphore* semaphore_; 243 bool was_sample_stack_called_; 244 }; 245 246 247 } // namespace 248 249 TEST(ProfMultipleThreads) { 250 TestSampler* sampler = NULL; 251 { 252 v8::Locker locker; 253 sampler = new TestSampler(CcTest::i_isolate()); 254 sampler->Start(); 255 CHECK(sampler->IsActive()); 256 } 257 258 LoopingJsThread jsThread(CcTest::i_isolate()); 259 jsThread.Start(); 260 LoopingNonJsThread nonJsThread(CcTest::i_isolate()); 261 nonJsThread.Start(); 262 263 CHECK(!sampler->WasSampleStackCalled()); 264 jsThread.WaitForRunning(); 265 jsThread.SendSigProf(); 266 CHECK(sampler->WaitForTick()); 267 CHECK(sampler->WasSampleStackCalled()); 268 sampler->Reset(); 269 CHECK(!sampler->WasSampleStackCalled()); 270 nonJsThread.WaitForRunning(); 271 nonJsThread.SendSigProf(); 272 CHECK(!sampler->WaitForTick()); 273 CHECK(!sampler->WasSampleStackCalled()); 274 sampler->Stop(); 275 276 jsThread.Stop(); 277 nonJsThread.Stop(); 278 jsThread.Join(); 279 nonJsThread.Join(); 280 281 delete sampler; 282 } 283 284 #endif // __linux__ 285 286 287 // Test for issue http://crbug.com/23768 in Chromium. 288 // Heap can contain scripts with already disposed external sources. 289 // We need to verify that LogCompiledFunctions doesn't crash on them. 290 namespace { 291 292 class SimpleExternalString : public v8::String::ExternalStringResource { 293 public: 294 explicit SimpleExternalString(const char* source) 295 : utf_source_(StrLength(source)) { 296 for (int i = 0; i < utf_source_.length(); ++i) 297 utf_source_[i] = source[i]; 298 } 299 virtual ~SimpleExternalString() {} 300 virtual size_t length() const { return utf_source_.length(); } 301 virtual const uint16_t* data() const { return utf_source_.start(); } 302 private: 303 i::ScopedVector<uint16_t> utf_source_; 304 }; 305 306 } // namespace 307 308 TEST(Issue23768) { 309 v8::HandleScope scope(CcTest::isolate()); 310 v8::Local<v8::Context> env = v8::Context::New(CcTest::isolate()); 311 env->Enter(); 312 313 SimpleExternalString source_ext_str("(function ext() {})();"); 314 v8::Local<v8::String> source = 315 v8::String::NewExternalTwoByte(CcTest::isolate(), &source_ext_str) 316 .ToLocalChecked(); 317 // Script needs to have a name in order to trigger InitLineEnds execution. 318 v8::Local<v8::String> origin = 319 v8::String::NewFromUtf8(CcTest::isolate(), "issue-23768-test", 320 v8::NewStringType::kNormal) 321 .ToLocalChecked(); 322 v8::Local<v8::Script> evil_script = CompileWithOrigin(source, origin); 323 CHECK(!evil_script.IsEmpty()); 324 CHECK(!evil_script->Run(env).IsEmpty()); 325 i::Handle<i::ExternalTwoByteString> i_source( 326 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source))); 327 // This situation can happen if source was an external string disposed 328 // by its owner. 329 i_source->set_resource(NULL); 330 331 // Must not crash. 332 CcTest::i_isolate()->logger()->LogCompiledFunctions(); 333 } 334 335 336 static void ObjMethod1(const v8::FunctionCallbackInfo<v8::Value>& args) { 337 } 338 339 340 TEST(LogCallbacks) { 341 SETUP_FLAGS(); 342 v8::Isolate::CreateParams create_params; 343 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 344 v8::Isolate* isolate = v8::Isolate::New(create_params); 345 { 346 ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate); 347 Logger* logger = initialize_logger.logger(); 348 349 v8::Local<v8::FunctionTemplate> obj = v8::Local<v8::FunctionTemplate>::New( 350 isolate, v8::FunctionTemplate::New(isolate)); 351 obj->SetClassName(v8_str("Obj")); 352 v8::Local<v8::ObjectTemplate> proto = obj->PrototypeTemplate(); 353 v8::Local<v8::Signature> signature = v8::Signature::New(isolate, obj); 354 proto->Set(v8_str("method1"), 355 v8::FunctionTemplate::New(isolate, ObjMethod1, 356 v8::Local<v8::Value>(), signature), 357 static_cast<v8::PropertyAttribute>(v8::DontDelete)); 358 359 initialize_logger.env() 360 ->Global() 361 ->Set(initialize_logger.env(), v8_str("Obj"), 362 obj->GetFunction(initialize_logger.env()).ToLocalChecked()) 363 .FromJust(); 364 CompileRun("Obj.prototype.method1.toString();"); 365 366 logger->LogCompiledFunctions(); 367 368 bool exists = false; 369 i::Vector<const char> log( 370 i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); 371 CHECK(exists); 372 373 i::EmbeddedVector<char, 100> ref_data; 374 i::SNPrintF(ref_data, 375 "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"method1\"", 376 reinterpret_cast<intptr_t>(ObjMethod1)); 377 378 CHECK(StrNStr(log.start(), ref_data.start(), log.length())); 379 log.Dispose(); 380 } 381 isolate->Dispose(); 382 } 383 384 385 static void Prop1Getter(v8::Local<v8::String> property, 386 const v8::PropertyCallbackInfo<v8::Value>& info) { 387 } 388 389 static void Prop1Setter(v8::Local<v8::String> property, 390 v8::Local<v8::Value> value, 391 const v8::PropertyCallbackInfo<void>& info) { 392 } 393 394 static void Prop2Getter(v8::Local<v8::String> property, 395 const v8::PropertyCallbackInfo<v8::Value>& info) { 396 } 397 398 399 TEST(LogAccessorCallbacks) { 400 SETUP_FLAGS(); 401 v8::Isolate::CreateParams create_params; 402 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 403 v8::Isolate* isolate = v8::Isolate::New(create_params); 404 { 405 ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate); 406 Logger* logger = initialize_logger.logger(); 407 408 v8::Local<v8::FunctionTemplate> obj = v8::Local<v8::FunctionTemplate>::New( 409 isolate, v8::FunctionTemplate::New(isolate)); 410 obj->SetClassName(v8_str("Obj")); 411 v8::Local<v8::ObjectTemplate> inst = obj->InstanceTemplate(); 412 inst->SetAccessor(v8_str("prop1"), Prop1Getter, Prop1Setter); 413 inst->SetAccessor(v8_str("prop2"), Prop2Getter); 414 415 logger->LogAccessorCallbacks(); 416 417 bool exists = false; 418 i::Vector<const char> log( 419 i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); 420 CHECK(exists); 421 422 EmbeddedVector<char, 100> prop1_getter_record; 423 i::SNPrintF(prop1_getter_record, 424 "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"get prop1\"", 425 reinterpret_cast<intptr_t>(Prop1Getter)); 426 CHECK(StrNStr(log.start(), prop1_getter_record.start(), log.length())); 427 428 EmbeddedVector<char, 100> prop1_setter_record; 429 i::SNPrintF(prop1_setter_record, 430 "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"set prop1\"", 431 reinterpret_cast<intptr_t>(Prop1Setter)); 432 CHECK(StrNStr(log.start(), prop1_setter_record.start(), log.length())); 433 434 EmbeddedVector<char, 100> prop2_getter_record; 435 i::SNPrintF(prop2_getter_record, 436 "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"get prop2\"", 437 reinterpret_cast<intptr_t>(Prop2Getter)); 438 CHECK(StrNStr(log.start(), prop2_getter_record.start(), log.length())); 439 log.Dispose(); 440 } 441 isolate->Dispose(); 442 } 443 444 445 typedef i::NativesCollection<i::TEST> TestSources; 446 447 448 // Test that logging of code create / move events is equivalent to traversal of 449 // a resulting heap. 450 TEST(EquivalenceOfLoggingAndTraversal) { 451 // This test needs to be run on a "clean" V8 to ensure that snapshot log 452 // is loaded. This is always true when running using tools/test.py because 453 // it launches a new cctest instance for every test. To be sure that launching 454 // cctest manually also works, please be sure that no tests below 455 // are using V8. 456 457 // Start with profiling to capture all code events from the beginning. 458 SETUP_FLAGS(); 459 v8::Isolate::CreateParams create_params; 460 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 461 v8::Isolate* isolate = v8::Isolate::New(create_params); 462 { 463 ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate); 464 Logger* logger = initialize_logger.logger(); 465 466 // Compile and run a function that creates other functions. 467 CompileRun( 468 "(function f(obj) {\n" 469 " obj.test =\n" 470 " (function a(j) { return function b() { return j; } })(100);\n" 471 "})(this);"); 472 logger->StopProfiler(); 473 reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage( 474 i::Heap::kMakeHeapIterableMask); 475 logger->StringEvent("test-logging-done", ""); 476 477 // Iterate heap to find compiled functions, will write to log. 478 logger->LogCompiledFunctions(); 479 logger->StringEvent("test-traversal-done", ""); 480 481 bool exists = false; 482 i::Vector<const char> log( 483 i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); 484 CHECK(exists); 485 v8::Local<v8::String> log_str = 486 v8::String::NewFromUtf8(isolate, log.start(), 487 v8::NewStringType::kNormal, log.length()) 488 .ToLocalChecked(); 489 initialize_logger.env() 490 ->Global() 491 ->Set(initialize_logger.env(), v8_str("_log"), log_str) 492 .FromJust(); 493 494 i::Vector<const char> source = TestSources::GetScriptsSource(); 495 v8::Local<v8::String> source_str = 496 v8::String::NewFromUtf8(isolate, source.start(), 497 v8::NewStringType::kNormal, source.length()) 498 .ToLocalChecked(); 499 v8::TryCatch try_catch(isolate); 500 v8::Local<v8::Script> script = CompileWithOrigin(source_str, ""); 501 if (script.IsEmpty()) { 502 v8::String::Utf8Value exception(try_catch.Exception()); 503 printf("compile: %s\n", *exception); 504 CHECK(false); 505 } 506 v8::Local<v8::Value> result; 507 if (!script->Run(initialize_logger.env()).ToLocal(&result)) { 508 v8::String::Utf8Value exception(try_catch.Exception()); 509 printf("run: %s\n", *exception); 510 CHECK(false); 511 } 512 // The result either be a "true" literal or problem description. 513 if (!result->IsTrue()) { 514 v8::Local<v8::String> s = 515 result->ToString(initialize_logger.env()).ToLocalChecked(); 516 i::ScopedVector<char> data(s->Utf8Length() + 1); 517 CHECK(data.start()); 518 s->WriteUtf8(data.start()); 519 printf("%s\n", data.start()); 520 // Make sure that our output is written prior crash due to CHECK failure. 521 fflush(stdout); 522 CHECK(false); 523 } 524 } 525 isolate->Dispose(); 526 } 527 528 529 TEST(LogVersion) { 530 SETUP_FLAGS(); 531 v8::Isolate::CreateParams create_params; 532 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 533 v8::Isolate* isolate = v8::Isolate::New(create_params); 534 { 535 ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate); 536 bool exists = false; 537 i::Vector<const char> log( 538 i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); 539 CHECK(exists); 540 i::EmbeddedVector<char, 100> ref_data; 541 i::SNPrintF(ref_data, "v8-version,%d,%d,%d,%d,%d", i::Version::GetMajor(), 542 i::Version::GetMinor(), i::Version::GetBuild(), 543 i::Version::GetPatch(), i::Version::IsCandidate()); 544 CHECK(StrNStr(log.start(), ref_data.start(), log.length())); 545 log.Dispose(); 546 } 547 isolate->Dispose(); 548 } 549 550 551 // https://crbug.com/539892 552 // CodeCreateEvents with really large names should not crash. 553 TEST(Issue539892) { 554 class : public i::CodeEventLogger { 555 public: 556 virtual void CodeMoveEvent(Address from, Address to) {} 557 virtual void CodeDeleteEvent(Address from) {} 558 virtual void CodeDisableOptEvent(i::Code* code, 559 i::SharedFunctionInfo* shared) {} 560 561 private: 562 virtual void LogRecordedBuffer(i::Code* code, i::SharedFunctionInfo* shared, 563 const char* name, int length) {} 564 } code_event_logger; 565 SETUP_FLAGS(); 566 v8::Isolate::CreateParams create_params; 567 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 568 v8::Isolate* isolate = v8::Isolate::New(create_params); 569 570 { 571 ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate); 572 Logger* logger = initialize_logger.logger(); 573 logger->addCodeEventListener(&code_event_logger); 574 575 // Function with a really large name. 576 const char* source_text = 577 "(function " 578 "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 579 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 580 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 581 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 582 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 583 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 584 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 585 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 586 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 587 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 588 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 589 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 590 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 591 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 592 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 593 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 594 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac" 595 "(){})();"; 596 597 CompileRun(source_text); 598 599 // Must not crash. 600 logger->LogCompiledFunctions(); 601 } 602 isolate->Dispose(); 603 } 604