1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <stdarg.h> 6 7 #include "src/v8.h" 8 9 #include "src/bootstrapper.h" 10 #include "src/code-stubs.h" 11 #include "src/cpu-profiler.h" 12 #include "src/deoptimizer.h" 13 #include "src/global-handles.h" 14 #include "src/log.h" 15 #include "src/log-utils.h" 16 #include "src/macro-assembler.h" 17 #include "src/platform.h" 18 #include "src/runtime-profiler.h" 19 #include "src/serialize.h" 20 #include "src/string-stream.h" 21 #include "src/vm-state-inl.h" 22 23 namespace v8 { 24 namespace internal { 25 26 27 #define DECLARE_EVENT(ignore1, name) name, 28 static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = { 29 LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT) 30 }; 31 #undef DECLARE_EVENT 32 33 34 #define CALL_LISTENERS(Call) \ 35 for (int i = 0; i < listeners_.length(); ++i) { \ 36 listeners_[i]->Call; \ 37 } 38 39 #define PROFILER_LOG(Call) \ 40 do { \ 41 CpuProfiler* cpu_profiler = isolate_->cpu_profiler(); \ 42 if (cpu_profiler->is_profiling()) { \ 43 cpu_profiler->Call; \ 44 } \ 45 } while (false); 46 47 // ComputeMarker must only be used when SharedFunctionInfo is known. 48 static const char* ComputeMarker(Code* code) { 49 switch (code->kind()) { 50 case Code::FUNCTION: return code->optimizable() ? "~" : ""; 51 case Code::OPTIMIZED_FUNCTION: return "*"; 52 default: return ""; 53 } 54 } 55 56 57 class CodeEventLogger::NameBuffer { 58 public: 59 NameBuffer() { Reset(); } 60 61 void Reset() { 62 utf8_pos_ = 0; 63 } 64 65 void Init(Logger::LogEventsAndTags tag) { 66 Reset(); 67 AppendBytes(kLogEventsNames[tag]); 68 AppendByte(':'); 69 } 70 71 void AppendName(Name* name) { 72 if (name->IsString()) { 73 AppendString(String::cast(name)); 74 } else { 75 Symbol* symbol = Symbol::cast(name); 76 AppendBytes("symbol("); 77 if (!symbol->name()->IsUndefined()) { 78 AppendBytes("\""); 79 AppendString(String::cast(symbol->name())); 80 AppendBytes("\" "); 81 } 82 AppendBytes("hash "); 83 AppendHex(symbol->Hash()); 84 AppendByte(')'); 85 } 86 } 87 88 void AppendString(String* str) { 89 if (str == NULL) return; 90 int uc16_length = Min(str->length(), kUtf16BufferSize); 91 String::WriteToFlat(str, utf16_buffer, 0, uc16_length); 92 int previous = unibrow::Utf16::kNoPreviousCharacter; 93 for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) { 94 uc16 c = utf16_buffer[i]; 95 if (c <= unibrow::Utf8::kMaxOneByteChar) { 96 utf8_buffer_[utf8_pos_++] = static_cast<char>(c); 97 } else { 98 int char_length = unibrow::Utf8::Length(c, previous); 99 if (utf8_pos_ + char_length > kUtf8BufferSize) break; 100 unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous); 101 utf8_pos_ += char_length; 102 } 103 previous = c; 104 } 105 } 106 107 void AppendBytes(const char* bytes, int size) { 108 size = Min(size, kUtf8BufferSize - utf8_pos_); 109 MemCopy(utf8_buffer_ + utf8_pos_, bytes, size); 110 utf8_pos_ += size; 111 } 112 113 void AppendBytes(const char* bytes) { 114 AppendBytes(bytes, StrLength(bytes)); 115 } 116 117 void AppendByte(char c) { 118 if (utf8_pos_ >= kUtf8BufferSize) return; 119 utf8_buffer_[utf8_pos_++] = c; 120 } 121 122 void AppendInt(int n) { 123 Vector<char> buffer(utf8_buffer_ + utf8_pos_, 124 kUtf8BufferSize - utf8_pos_); 125 int size = SNPrintF(buffer, "%d", n); 126 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) { 127 utf8_pos_ += size; 128 } 129 } 130 131 void AppendHex(uint32_t n) { 132 Vector<char> buffer(utf8_buffer_ + utf8_pos_, 133 kUtf8BufferSize - utf8_pos_); 134 int size = SNPrintF(buffer, "%x", n); 135 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) { 136 utf8_pos_ += size; 137 } 138 } 139 140 const char* get() { return utf8_buffer_; } 141 int size() const { return utf8_pos_; } 142 143 private: 144 static const int kUtf8BufferSize = 512; 145 static const int kUtf16BufferSize = 128; 146 147 int utf8_pos_; 148 char utf8_buffer_[kUtf8BufferSize]; 149 uc16 utf16_buffer[kUtf16BufferSize]; 150 }; 151 152 153 CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { } 154 155 CodeEventLogger::~CodeEventLogger() { delete name_buffer_; } 156 157 158 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag, 159 Code* code, 160 const char* comment) { 161 name_buffer_->Init(tag); 162 name_buffer_->AppendBytes(comment); 163 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size()); 164 } 165 166 167 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag, 168 Code* code, 169 Name* name) { 170 name_buffer_->Init(tag); 171 name_buffer_->AppendName(name); 172 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size()); 173 } 174 175 176 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag, 177 Code* code, 178 SharedFunctionInfo* shared, 179 CompilationInfo* info, 180 Name* name) { 181 name_buffer_->Init(tag); 182 name_buffer_->AppendBytes(ComputeMarker(code)); 183 name_buffer_->AppendName(name); 184 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size()); 185 } 186 187 188 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag, 189 Code* code, 190 SharedFunctionInfo* shared, 191 CompilationInfo* info, 192 Name* source, int line, int column) { 193 name_buffer_->Init(tag); 194 name_buffer_->AppendBytes(ComputeMarker(code)); 195 name_buffer_->AppendString(shared->DebugName()); 196 name_buffer_->AppendByte(' '); 197 if (source->IsString()) { 198 name_buffer_->AppendString(String::cast(source)); 199 } else { 200 name_buffer_->AppendBytes("symbol(hash "); 201 name_buffer_->AppendHex(Name::cast(source)->Hash()); 202 name_buffer_->AppendByte(')'); 203 } 204 name_buffer_->AppendByte(':'); 205 name_buffer_->AppendInt(line); 206 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size()); 207 } 208 209 210 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag, 211 Code* code, 212 int args_count) { 213 name_buffer_->Init(tag); 214 name_buffer_->AppendInt(args_count); 215 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size()); 216 } 217 218 219 void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) { 220 name_buffer_->Init(Logger::REG_EXP_TAG); 221 name_buffer_->AppendString(source); 222 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size()); 223 } 224 225 226 // Linux perf tool logging support 227 class PerfBasicLogger : public CodeEventLogger { 228 public: 229 PerfBasicLogger(); 230 virtual ~PerfBasicLogger(); 231 232 virtual void CodeMoveEvent(Address from, Address to) { } 233 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } 234 virtual void CodeDeleteEvent(Address from) { } 235 236 private: 237 virtual void LogRecordedBuffer(Code* code, 238 SharedFunctionInfo* shared, 239 const char* name, 240 int length); 241 242 // Extension added to V8 log file name to get the low-level log name. 243 static const char kFilenameFormatString[]; 244 static const int kFilenameBufferPadding; 245 246 // File buffer size of the low-level log. We don't use the default to 247 // minimize the associated overhead. 248 static const int kLogBufferSize = 2 * MB; 249 250 FILE* perf_output_handle_; 251 }; 252 253 const char PerfBasicLogger::kFilenameFormatString[] = "/tmp/perf-%d.map"; 254 // Extra space for the PID in the filename 255 const int PerfBasicLogger::kFilenameBufferPadding = 16; 256 257 PerfBasicLogger::PerfBasicLogger() 258 : perf_output_handle_(NULL) { 259 // Open the perf JIT dump file. 260 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding; 261 ScopedVector<char> perf_dump_name(bufferSize); 262 int size = SNPrintF( 263 perf_dump_name, 264 kFilenameFormatString, 265 OS::GetCurrentProcessId()); 266 CHECK_NE(size, -1); 267 perf_output_handle_ = OS::FOpen(perf_dump_name.start(), OS::LogFileOpenMode); 268 CHECK_NE(perf_output_handle_, NULL); 269 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize); 270 } 271 272 273 PerfBasicLogger::~PerfBasicLogger() { 274 fclose(perf_output_handle_); 275 perf_output_handle_ = NULL; 276 } 277 278 279 void PerfBasicLogger::LogRecordedBuffer(Code* code, 280 SharedFunctionInfo*, 281 const char* name, 282 int length) { 283 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); 284 285 OS::FPrint(perf_output_handle_, "%llx %x %.*s\n", 286 reinterpret_cast<uint64_t>(code->instruction_start()), 287 code->instruction_size(), 288 length, name); 289 } 290 291 292 // Linux perf tool logging support 293 class PerfJitLogger : public CodeEventLogger { 294 public: 295 PerfJitLogger(); 296 virtual ~PerfJitLogger(); 297 298 virtual void CodeMoveEvent(Address from, Address to) { } 299 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } 300 virtual void CodeDeleteEvent(Address from) { } 301 302 private: 303 virtual void LogRecordedBuffer(Code* code, 304 SharedFunctionInfo* shared, 305 const char* name, 306 int length); 307 308 // Extension added to V8 log file name to get the low-level log name. 309 static const char kFilenameFormatString[]; 310 static const int kFilenameBufferPadding; 311 312 // File buffer size of the low-level log. We don't use the default to 313 // minimize the associated overhead. 314 static const int kLogBufferSize = 2 * MB; 315 316 void LogWriteBytes(const char* bytes, int size); 317 void LogWriteHeader(); 318 319 static const uint32_t kJitHeaderMagic = 0x4F74496A; 320 static const uint32_t kJitHeaderVersion = 0x2; 321 static const uint32_t kElfMachIA32 = 3; 322 static const uint32_t kElfMachX64 = 62; 323 static const uint32_t kElfMachARM = 40; 324 static const uint32_t kElfMachMIPS = 10; 325 static const uint32_t kElfMachX87 = 3; 326 327 struct jitheader { 328 uint32_t magic; 329 uint32_t version; 330 uint32_t total_size; 331 uint32_t elf_mach; 332 uint32_t pad1; 333 uint32_t pid; 334 uint64_t timestamp; 335 }; 336 337 enum jit_record_type { 338 JIT_CODE_LOAD = 0 339 // JIT_CODE_UNLOAD = 1, 340 // JIT_CODE_CLOSE = 2, 341 // JIT_CODE_DEBUG_INFO = 3, 342 // JIT_CODE_PAGE_MAP = 4, 343 // JIT_CODE_MAX = 5 344 }; 345 346 struct jr_code_load { 347 uint32_t id; 348 uint32_t total_size; 349 uint64_t timestamp; 350 uint64_t vma; 351 uint64_t code_addr; 352 uint32_t code_size; 353 uint32_t align; 354 }; 355 356 uint32_t GetElfMach() { 357 #if V8_TARGET_ARCH_IA32 358 return kElfMachIA32; 359 #elif V8_TARGET_ARCH_X64 360 return kElfMachX64; 361 #elif V8_TARGET_ARCH_ARM 362 return kElfMachARM; 363 #elif V8_TARGET_ARCH_MIPS 364 return kElfMachMIPS; 365 #elif V8_TARGET_ARCH_X87 366 return kElfMachX87; 367 #else 368 UNIMPLEMENTED(); 369 return 0; 370 #endif 371 } 372 373 FILE* perf_output_handle_; 374 }; 375 376 const char PerfJitLogger::kFilenameFormatString[] = "/tmp/jit-%d.dump"; 377 378 // Extra padding for the PID in the filename 379 const int PerfJitLogger::kFilenameBufferPadding = 16; 380 381 PerfJitLogger::PerfJitLogger() 382 : perf_output_handle_(NULL) { 383 // Open the perf JIT dump file. 384 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding; 385 ScopedVector<char> perf_dump_name(bufferSize); 386 int size = SNPrintF( 387 perf_dump_name, 388 kFilenameFormatString, 389 OS::GetCurrentProcessId()); 390 CHECK_NE(size, -1); 391 perf_output_handle_ = OS::FOpen(perf_dump_name.start(), OS::LogFileOpenMode); 392 CHECK_NE(perf_output_handle_, NULL); 393 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize); 394 395 LogWriteHeader(); 396 } 397 398 399 PerfJitLogger::~PerfJitLogger() { 400 fclose(perf_output_handle_); 401 perf_output_handle_ = NULL; 402 } 403 404 405 void PerfJitLogger::LogRecordedBuffer(Code* code, 406 SharedFunctionInfo*, 407 const char* name, 408 int length) { 409 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); 410 ASSERT(perf_output_handle_ != NULL); 411 412 const char* code_name = name; 413 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start()); 414 uint32_t code_size = code->instruction_size(); 415 416 static const char string_terminator[] = "\0"; 417 418 jr_code_load code_load; 419 code_load.id = JIT_CODE_LOAD; 420 code_load.total_size = sizeof(code_load) + length + 1 + code_size; 421 code_load.timestamp = 422 static_cast<uint64_t>(OS::TimeCurrentMillis() * 1000.0); 423 code_load.vma = 0x0; // Our addresses are absolute. 424 code_load.code_addr = reinterpret_cast<uint64_t>(code->instruction_start()); 425 code_load.code_size = code_size; 426 code_load.align = 0; 427 428 LogWriteBytes(reinterpret_cast<const char*>(&code_load), sizeof(code_load)); 429 LogWriteBytes(code_name, length); 430 LogWriteBytes(string_terminator, 1); 431 LogWriteBytes(reinterpret_cast<const char*>(code_pointer), code_size); 432 } 433 434 435 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { 436 size_t rv = fwrite(bytes, 1, size, perf_output_handle_); 437 ASSERT(static_cast<size_t>(size) == rv); 438 USE(rv); 439 } 440 441 442 void PerfJitLogger::LogWriteHeader() { 443 ASSERT(perf_output_handle_ != NULL); 444 jitheader header; 445 header.magic = kJitHeaderMagic; 446 header.version = kJitHeaderVersion; 447 header.total_size = sizeof(jitheader); 448 header.pad1 = 0xdeadbeef; 449 header.elf_mach = GetElfMach(); 450 header.pid = OS::GetCurrentProcessId(); 451 header.timestamp = static_cast<uint64_t>(OS::TimeCurrentMillis() * 1000.0); 452 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); 453 } 454 455 456 // Low-level logging support. 457 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call; 458 459 class LowLevelLogger : public CodeEventLogger { 460 public: 461 explicit LowLevelLogger(const char* file_name); 462 virtual ~LowLevelLogger(); 463 464 virtual void CodeMoveEvent(Address from, Address to); 465 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } 466 virtual void CodeDeleteEvent(Address from); 467 virtual void SnapshotPositionEvent(Address addr, int pos); 468 virtual void CodeMovingGCEvent(); 469 470 private: 471 virtual void LogRecordedBuffer(Code* code, 472 SharedFunctionInfo* shared, 473 const char* name, 474 int length); 475 476 // Low-level profiling event structures. 477 struct CodeCreateStruct { 478 static const char kTag = 'C'; 479 480 int32_t name_size; 481 Address code_address; 482 int32_t code_size; 483 }; 484 485 486 struct CodeMoveStruct { 487 static const char kTag = 'M'; 488 489 Address from_address; 490 Address to_address; 491 }; 492 493 494 struct CodeDeleteStruct { 495 static const char kTag = 'D'; 496 497 Address address; 498 }; 499 500 501 struct SnapshotPositionStruct { 502 static const char kTag = 'P'; 503 504 Address address; 505 int32_t position; 506 }; 507 508 509 static const char kCodeMovingGCTag = 'G'; 510 511 512 // Extension added to V8 log file name to get the low-level log name. 513 static const char kLogExt[]; 514 515 // File buffer size of the low-level log. We don't use the default to 516 // minimize the associated overhead. 517 static const int kLogBufferSize = 2 * MB; 518 519 void LogCodeInfo(); 520 void LogWriteBytes(const char* bytes, int size); 521 522 template <typename T> 523 void LogWriteStruct(const T& s) { 524 char tag = T::kTag; 525 LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag)); 526 LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s)); 527 } 528 529 FILE* ll_output_handle_; 530 }; 531 532 const char LowLevelLogger::kLogExt[] = ".ll"; 533 534 LowLevelLogger::LowLevelLogger(const char* name) 535 : ll_output_handle_(NULL) { 536 // Open the low-level log file. 537 size_t len = strlen(name); 538 ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt))); 539 MemCopy(ll_name.start(), name, len); 540 MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt)); 541 ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode); 542 setvbuf(ll_output_handle_, NULL, _IOFBF, kLogBufferSize); 543 544 LogCodeInfo(); 545 } 546 547 548 LowLevelLogger::~LowLevelLogger() { 549 fclose(ll_output_handle_); 550 ll_output_handle_ = NULL; 551 } 552 553 554 void LowLevelLogger::LogCodeInfo() { 555 #if V8_TARGET_ARCH_IA32 556 const char arch[] = "ia32"; 557 #elif V8_TARGET_ARCH_X64 558 const char arch[] = "x64"; 559 #elif V8_TARGET_ARCH_ARM 560 const char arch[] = "arm"; 561 #elif V8_TARGET_ARCH_MIPS 562 const char arch[] = "mips"; 563 #elif V8_TARGET_ARCH_X87 564 const char arch[] = "x87"; 565 #else 566 const char arch[] = "unknown"; 567 #endif 568 LogWriteBytes(arch, sizeof(arch)); 569 } 570 571 572 void LowLevelLogger::LogRecordedBuffer(Code* code, 573 SharedFunctionInfo*, 574 const char* name, 575 int length) { 576 CodeCreateStruct event; 577 event.name_size = length; 578 event.code_address = code->instruction_start(); 579 ASSERT(event.code_address == code->address() + Code::kHeaderSize); 580 event.code_size = code->instruction_size(); 581 LogWriteStruct(event); 582 LogWriteBytes(name, length); 583 LogWriteBytes( 584 reinterpret_cast<const char*>(code->instruction_start()), 585 code->instruction_size()); 586 } 587 588 589 void LowLevelLogger::CodeMoveEvent(Address from, Address to) { 590 CodeMoveStruct event; 591 event.from_address = from + Code::kHeaderSize; 592 event.to_address = to + Code::kHeaderSize; 593 LogWriteStruct(event); 594 } 595 596 597 void LowLevelLogger::CodeDeleteEvent(Address from) { 598 CodeDeleteStruct event; 599 event.address = from + Code::kHeaderSize; 600 LogWriteStruct(event); 601 } 602 603 604 void LowLevelLogger::SnapshotPositionEvent(Address addr, int pos) { 605 SnapshotPositionStruct event; 606 event.address = addr + Code::kHeaderSize; 607 event.position = pos; 608 LogWriteStruct(event); 609 } 610 611 612 void LowLevelLogger::LogWriteBytes(const char* bytes, int size) { 613 size_t rv = fwrite(bytes, 1, size, ll_output_handle_); 614 ASSERT(static_cast<size_t>(size) == rv); 615 USE(rv); 616 } 617 618 619 void LowLevelLogger::CodeMovingGCEvent() { 620 const char tag = kCodeMovingGCTag; 621 622 LogWriteBytes(&tag, sizeof(tag)); 623 } 624 625 626 #define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call; 627 628 629 class JitLogger : public CodeEventLogger { 630 public: 631 explicit JitLogger(JitCodeEventHandler code_event_handler); 632 633 virtual void CodeMoveEvent(Address from, Address to); 634 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } 635 virtual void CodeDeleteEvent(Address from); 636 virtual void AddCodeLinePosInfoEvent( 637 void* jit_handler_data, 638 int pc_offset, 639 int position, 640 JitCodeEvent::PositionType position_type); 641 642 void* StartCodePosInfoEvent(); 643 void EndCodePosInfoEvent(Code* code, void* jit_handler_data); 644 645 private: 646 virtual void LogRecordedBuffer(Code* code, 647 SharedFunctionInfo* shared, 648 const char* name, 649 int length); 650 651 JitCodeEventHandler code_event_handler_; 652 }; 653 654 655 JitLogger::JitLogger(JitCodeEventHandler code_event_handler) 656 : code_event_handler_(code_event_handler) { 657 } 658 659 660 void JitLogger::LogRecordedBuffer(Code* code, 661 SharedFunctionInfo* shared, 662 const char* name, 663 int length) { 664 JitCodeEvent event; 665 memset(&event, 0, sizeof(event)); 666 event.type = JitCodeEvent::CODE_ADDED; 667 event.code_start = code->instruction_start(); 668 event.code_len = code->instruction_size(); 669 Handle<Script> script_handle; 670 if (shared && shared->script()->IsScript()) { 671 script_handle = Handle<Script>(Script::cast(shared->script())); 672 } 673 event.script = ToApiHandle<v8::Script>(script_handle); 674 event.name.str = name; 675 event.name.len = length; 676 code_event_handler_(&event); 677 } 678 679 680 void JitLogger::CodeMoveEvent(Address from, Address to) { 681 Code* from_code = Code::cast(HeapObject::FromAddress(from)); 682 683 JitCodeEvent event; 684 event.type = JitCodeEvent::CODE_MOVED; 685 event.code_start = from_code->instruction_start(); 686 event.code_len = from_code->instruction_size(); 687 688 // Calculate the header size. 689 const size_t header_size = 690 from_code->instruction_start() - reinterpret_cast<byte*>(from_code); 691 692 // Calculate the new start address of the instructions. 693 event.new_code_start = 694 reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size; 695 696 code_event_handler_(&event); 697 } 698 699 700 void JitLogger::CodeDeleteEvent(Address from) { 701 Code* from_code = Code::cast(HeapObject::FromAddress(from)); 702 703 JitCodeEvent event; 704 event.type = JitCodeEvent::CODE_REMOVED; 705 event.code_start = from_code->instruction_start(); 706 event.code_len = from_code->instruction_size(); 707 708 code_event_handler_(&event); 709 } 710 711 void JitLogger::AddCodeLinePosInfoEvent( 712 void* jit_handler_data, 713 int pc_offset, 714 int position, 715 JitCodeEvent::PositionType position_type) { 716 JitCodeEvent event; 717 memset(&event, 0, sizeof(event)); 718 event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO; 719 event.user_data = jit_handler_data; 720 event.line_info.offset = pc_offset; 721 event.line_info.pos = position; 722 event.line_info.position_type = position_type; 723 724 code_event_handler_(&event); 725 } 726 727 728 void* JitLogger::StartCodePosInfoEvent() { 729 JitCodeEvent event; 730 memset(&event, 0, sizeof(event)); 731 event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING; 732 733 code_event_handler_(&event); 734 return event.user_data; 735 } 736 737 738 void JitLogger::EndCodePosInfoEvent(Code* code, void* jit_handler_data) { 739 JitCodeEvent event; 740 memset(&event, 0, sizeof(event)); 741 event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING; 742 event.code_start = code->instruction_start(); 743 event.user_data = jit_handler_data; 744 745 code_event_handler_(&event); 746 } 747 748 749 // The Profiler samples pc and sp values for the main thread. 750 // Each sample is appended to a circular buffer. 751 // An independent thread removes data and writes it to the log. 752 // This design minimizes the time spent in the sampler. 753 // 754 class Profiler: public Thread { 755 public: 756 explicit Profiler(Isolate* isolate); 757 void Engage(); 758 void Disengage(); 759 760 // Inserts collected profiling data into buffer. 761 void Insert(TickSample* sample) { 762 if (paused_) 763 return; 764 765 if (Succ(head_) == tail_) { 766 overflow_ = true; 767 } else { 768 buffer_[head_] = *sample; 769 head_ = Succ(head_); 770 buffer_semaphore_.Signal(); // Tell we have an element. 771 } 772 } 773 774 virtual void Run(); 775 776 // Pause and Resume TickSample data collection. 777 void pause() { paused_ = true; } 778 void resume() { paused_ = false; } 779 780 private: 781 // Waits for a signal and removes profiling data. 782 bool Remove(TickSample* sample) { 783 buffer_semaphore_.Wait(); // Wait for an element. 784 *sample = buffer_[tail_]; 785 bool result = overflow_; 786 tail_ = Succ(tail_); 787 overflow_ = false; 788 return result; 789 } 790 791 // Returns the next index in the cyclic buffer. 792 int Succ(int index) { return (index + 1) % kBufferSize; } 793 794 Isolate* isolate_; 795 // Cyclic buffer for communicating profiling samples 796 // between the signal handler and the worker thread. 797 static const int kBufferSize = 128; 798 TickSample buffer_[kBufferSize]; // Buffer storage. 799 int head_; // Index to the buffer head. 800 int tail_; // Index to the buffer tail. 801 bool overflow_; // Tell whether a buffer overflow has occurred. 802 // Sempahore used for buffer synchronization. 803 Semaphore buffer_semaphore_; 804 805 // Tells whether profiler is engaged, that is, processing thread is stated. 806 bool engaged_; 807 808 // Tells whether worker thread should continue running. 809 bool running_; 810 811 // Tells whether we are currently recording tick samples. 812 bool paused_; 813 }; 814 815 816 // 817 // Ticker used to provide ticks to the profiler and the sliding state 818 // window. 819 // 820 class Ticker: public Sampler { 821 public: 822 Ticker(Isolate* isolate, int interval): 823 Sampler(isolate, interval), 824 profiler_(NULL) {} 825 826 ~Ticker() { if (IsActive()) Stop(); } 827 828 virtual void Tick(TickSample* sample) { 829 if (profiler_) profiler_->Insert(sample); 830 } 831 832 void SetProfiler(Profiler* profiler) { 833 ASSERT(profiler_ == NULL); 834 profiler_ = profiler; 835 IncreaseProfilingDepth(); 836 if (!IsActive()) Start(); 837 } 838 839 void ClearProfiler() { 840 profiler_ = NULL; 841 if (IsActive()) Stop(); 842 DecreaseProfilingDepth(); 843 } 844 845 private: 846 Profiler* profiler_; 847 }; 848 849 850 // 851 // Profiler implementation. 852 // 853 Profiler::Profiler(Isolate* isolate) 854 : Thread("v8:Profiler"), 855 isolate_(isolate), 856 head_(0), 857 tail_(0), 858 overflow_(false), 859 buffer_semaphore_(0), 860 engaged_(false), 861 running_(false), 862 paused_(false) { 863 } 864 865 866 void Profiler::Engage() { 867 if (engaged_) return; 868 engaged_ = true; 869 870 std::vector<OS::SharedLibraryAddress> addresses = 871 OS::GetSharedLibraryAddresses(); 872 for (size_t i = 0; i < addresses.size(); ++i) { 873 LOG(isolate_, SharedLibraryEvent( 874 addresses[i].library_path, addresses[i].start, addresses[i].end)); 875 } 876 877 // Start thread processing the profiler buffer. 878 running_ = true; 879 Start(); 880 881 // Register to get ticks. 882 Logger* logger = isolate_->logger(); 883 logger->ticker_->SetProfiler(this); 884 885 logger->ProfilerBeginEvent(); 886 } 887 888 889 void Profiler::Disengage() { 890 if (!engaged_) return; 891 892 // Stop receiving ticks. 893 isolate_->logger()->ticker_->ClearProfiler(); 894 895 // Terminate the worker thread by setting running_ to false, 896 // inserting a fake element in the queue and then wait for 897 // the thread to terminate. 898 running_ = false; 899 TickSample sample; 900 // Reset 'paused_' flag, otherwise semaphore may not be signalled. 901 resume(); 902 Insert(&sample); 903 Join(); 904 905 LOG(isolate_, UncheckedStringEvent("profiler", "end")); 906 } 907 908 909 void Profiler::Run() { 910 TickSample sample; 911 bool overflow = Remove(&sample); 912 while (running_) { 913 LOG(isolate_, TickEvent(&sample, overflow)); 914 overflow = Remove(&sample); 915 } 916 } 917 918 919 // 920 // Logger class implementation. 921 // 922 923 Logger::Logger(Isolate* isolate) 924 : isolate_(isolate), 925 ticker_(NULL), 926 profiler_(NULL), 927 log_events_(NULL), 928 is_logging_(false), 929 log_(new Log(this)), 930 perf_basic_logger_(NULL), 931 perf_jit_logger_(NULL), 932 ll_logger_(NULL), 933 jit_logger_(NULL), 934 listeners_(5), 935 is_initialized_(false) { 936 } 937 938 939 Logger::~Logger() { 940 delete log_; 941 } 942 943 944 void Logger::addCodeEventListener(CodeEventListener* listener) { 945 ASSERT(!hasCodeEventListener(listener)); 946 listeners_.Add(listener); 947 } 948 949 950 void Logger::removeCodeEventListener(CodeEventListener* listener) { 951 ASSERT(hasCodeEventListener(listener)); 952 listeners_.RemoveElement(listener); 953 } 954 955 956 bool Logger::hasCodeEventListener(CodeEventListener* listener) { 957 return listeners_.Contains(listener); 958 } 959 960 961 void Logger::ProfilerBeginEvent() { 962 if (!log_->IsEnabled()) return; 963 Log::MessageBuilder msg(log_); 964 msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs); 965 msg.WriteToLogFile(); 966 } 967 968 969 void Logger::StringEvent(const char* name, const char* value) { 970 if (FLAG_log) UncheckedStringEvent(name, value); 971 } 972 973 974 void Logger::UncheckedStringEvent(const char* name, const char* value) { 975 if (!log_->IsEnabled()) return; 976 Log::MessageBuilder msg(log_); 977 msg.Append("%s,\"%s\"\n", name, value); 978 msg.WriteToLogFile(); 979 } 980 981 982 void Logger::IntEvent(const char* name, int value) { 983 if (FLAG_log) UncheckedIntEvent(name, value); 984 } 985 986 987 void Logger::IntPtrTEvent(const char* name, intptr_t value) { 988 if (FLAG_log) UncheckedIntPtrTEvent(name, value); 989 } 990 991 992 void Logger::UncheckedIntEvent(const char* name, int value) { 993 if (!log_->IsEnabled()) return; 994 Log::MessageBuilder msg(log_); 995 msg.Append("%s,%d\n", name, value); 996 msg.WriteToLogFile(); 997 } 998 999 1000 void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) { 1001 if (!log_->IsEnabled()) return; 1002 Log::MessageBuilder msg(log_); 1003 msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value); 1004 msg.WriteToLogFile(); 1005 } 1006 1007 1008 void Logger::HandleEvent(const char* name, Object** location) { 1009 if (!log_->IsEnabled() || !FLAG_log_handles) return; 1010 Log::MessageBuilder msg(log_); 1011 msg.Append("%s,0x%" V8PRIxPTR "\n", name, location); 1012 msg.WriteToLogFile(); 1013 } 1014 1015 1016 // ApiEvent is private so all the calls come from the Logger class. It is the 1017 // caller's responsibility to ensure that log is enabled and that 1018 // FLAG_log_api is true. 1019 void Logger::ApiEvent(const char* format, ...) { 1020 ASSERT(log_->IsEnabled() && FLAG_log_api); 1021 Log::MessageBuilder msg(log_); 1022 va_list ap; 1023 va_start(ap, format); 1024 msg.AppendVA(format, ap); 1025 va_end(ap); 1026 msg.WriteToLogFile(); 1027 } 1028 1029 1030 void Logger::ApiNamedSecurityCheck(Object* key) { 1031 if (!log_->IsEnabled() || !FLAG_log_api) return; 1032 if (key->IsString()) { 1033 SmartArrayPointer<char> str = 1034 String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1035 ApiEvent("api,check-security,\"%s\"\n", str.get()); 1036 } else if (key->IsSymbol()) { 1037 Symbol* symbol = Symbol::cast(key); 1038 if (symbol->name()->IsUndefined()) { 1039 ApiEvent("api,check-security,symbol(hash %x)\n", 1040 Symbol::cast(key)->Hash()); 1041 } else { 1042 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString( 1043 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1044 ApiEvent("api,check-security,symbol(\"%s\" hash %x)\n", 1045 str.get(), 1046 Symbol::cast(key)->Hash()); 1047 } 1048 } else if (key->IsUndefined()) { 1049 ApiEvent("api,check-security,undefined\n"); 1050 } else { 1051 ApiEvent("api,check-security,['no-name']\n"); 1052 } 1053 } 1054 1055 1056 void Logger::SharedLibraryEvent(const std::string& library_path, 1057 uintptr_t start, 1058 uintptr_t end) { 1059 if (!log_->IsEnabled() || !FLAG_prof) return; 1060 Log::MessageBuilder msg(log_); 1061 msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n", 1062 library_path.c_str(), 1063 start, 1064 end); 1065 msg.WriteToLogFile(); 1066 } 1067 1068 1069 void Logger::CodeDeoptEvent(Code* code) { 1070 if (!log_->IsEnabled()) return; 1071 ASSERT(FLAG_log_internal_timer_events); 1072 Log::MessageBuilder msg(log_); 1073 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds()); 1074 msg.Append("code-deopt,%ld,%d\n", since_epoch, code->CodeSize()); 1075 msg.WriteToLogFile(); 1076 } 1077 1078 1079 void Logger::CurrentTimeEvent() { 1080 if (!log_->IsEnabled()) return; 1081 ASSERT(FLAG_log_internal_timer_events); 1082 Log::MessageBuilder msg(log_); 1083 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds()); 1084 msg.Append("current-time,%ld\n", since_epoch); 1085 msg.WriteToLogFile(); 1086 } 1087 1088 1089 void Logger::TimerEvent(StartEnd se, const char* name) { 1090 if (!log_->IsEnabled()) return; 1091 ASSERT(FLAG_log_internal_timer_events); 1092 Log::MessageBuilder msg(log_); 1093 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds()); 1094 const char* format = (se == START) ? "timer-event-start,\"%s\",%ld\n" 1095 : "timer-event-end,\"%s\",%ld\n"; 1096 msg.Append(format, name, since_epoch); 1097 msg.WriteToLogFile(); 1098 } 1099 1100 1101 void Logger::EnterExternal(Isolate* isolate) { 1102 LOG(isolate, TimerEvent(START, TimerEventScope::v8_external)); 1103 ASSERT(isolate->current_vm_state() == JS); 1104 isolate->set_current_vm_state(EXTERNAL); 1105 } 1106 1107 1108 void Logger::LeaveExternal(Isolate* isolate) { 1109 LOG(isolate, TimerEvent(END, TimerEventScope::v8_external)); 1110 ASSERT(isolate->current_vm_state() == EXTERNAL); 1111 isolate->set_current_vm_state(JS); 1112 } 1113 1114 1115 void Logger::LogInternalEvents(const char* name, int se) { 1116 Isolate* isolate = Isolate::Current(); 1117 LOG(isolate, TimerEvent(static_cast<StartEnd>(se), name)); 1118 } 1119 1120 1121 void Logger::TimerEventScope::LogTimerEvent(StartEnd se) { 1122 isolate_->event_logger()(name_, se); 1123 } 1124 1125 1126 const char* Logger::TimerEventScope::v8_recompile_synchronous = 1127 "V8.RecompileSynchronous"; 1128 const char* Logger::TimerEventScope::v8_recompile_concurrent = 1129 "V8.RecompileConcurrent"; 1130 const char* Logger::TimerEventScope::v8_compile_full_code = 1131 "V8.CompileFullCode"; 1132 const char* Logger::TimerEventScope::v8_execute = "V8.Execute"; 1133 const char* Logger::TimerEventScope::v8_external = "V8.External"; 1134 const char* Logger::TimerEventScope::v8_ic_miss = "V8.IcMiss"; 1135 1136 1137 void Logger::LogRegExpSource(Handle<JSRegExp> regexp) { 1138 // Prints "/" + re.source + "/" + 1139 // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"") 1140 Log::MessageBuilder msg(log_); 1141 1142 Handle<Object> source = Object::GetProperty( 1143 isolate_, regexp, "source").ToHandleChecked(); 1144 if (!source->IsString()) { 1145 msg.Append("no source"); 1146 return; 1147 } 1148 1149 switch (regexp->TypeTag()) { 1150 case JSRegExp::ATOM: 1151 msg.Append('a'); 1152 break; 1153 default: 1154 break; 1155 } 1156 msg.Append('/'); 1157 msg.AppendDetailed(*Handle<String>::cast(source), false); 1158 msg.Append('/'); 1159 1160 // global flag 1161 Handle<Object> global = Object::GetProperty( 1162 isolate_, regexp, "global").ToHandleChecked(); 1163 if (global->IsTrue()) { 1164 msg.Append('g'); 1165 } 1166 // ignorecase flag 1167 Handle<Object> ignorecase = Object::GetProperty( 1168 isolate_, regexp, "ignoreCase").ToHandleChecked(); 1169 if (ignorecase->IsTrue()) { 1170 msg.Append('i'); 1171 } 1172 // multiline flag 1173 Handle<Object> multiline = Object::GetProperty( 1174 isolate_, regexp, "multiline").ToHandleChecked(); 1175 if (multiline->IsTrue()) { 1176 msg.Append('m'); 1177 } 1178 1179 msg.WriteToLogFile(); 1180 } 1181 1182 1183 void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) { 1184 if (!log_->IsEnabled() || !FLAG_log_regexp) return; 1185 Log::MessageBuilder msg(log_); 1186 msg.Append("regexp-compile,"); 1187 LogRegExpSource(regexp); 1188 msg.Append(in_cache ? ",hit\n" : ",miss\n"); 1189 msg.WriteToLogFile(); 1190 } 1191 1192 1193 void Logger::ApiIndexedSecurityCheck(uint32_t index) { 1194 if (!log_->IsEnabled() || !FLAG_log_api) return; 1195 ApiEvent("api,check-security,%u\n", index); 1196 } 1197 1198 1199 void Logger::ApiNamedPropertyAccess(const char* tag, 1200 JSObject* holder, 1201 Object* name) { 1202 ASSERT(name->IsName()); 1203 if (!log_->IsEnabled() || !FLAG_log_api) return; 1204 String* class_name_obj = holder->class_name(); 1205 SmartArrayPointer<char> class_name = 1206 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1207 if (name->IsString()) { 1208 SmartArrayPointer<char> property_name = 1209 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1210 ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, class_name.get(), 1211 property_name.get()); 1212 } else { 1213 Symbol* symbol = Symbol::cast(name); 1214 uint32_t hash = symbol->Hash(); 1215 if (symbol->name()->IsUndefined()) { 1216 ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, class_name.get(), hash); 1217 } else { 1218 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString( 1219 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1220 ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)\n", 1221 tag, class_name.get(), str.get(), hash); 1222 } 1223 } 1224 } 1225 1226 void Logger::ApiIndexedPropertyAccess(const char* tag, 1227 JSObject* holder, 1228 uint32_t index) { 1229 if (!log_->IsEnabled() || !FLAG_log_api) return; 1230 String* class_name_obj = holder->class_name(); 1231 SmartArrayPointer<char> class_name = 1232 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1233 ApiEvent("api,%s,\"%s\",%u\n", tag, class_name.get(), index); 1234 } 1235 1236 1237 void Logger::ApiObjectAccess(const char* tag, JSObject* object) { 1238 if (!log_->IsEnabled() || !FLAG_log_api) return; 1239 String* class_name_obj = object->class_name(); 1240 SmartArrayPointer<char> class_name = 1241 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1242 ApiEvent("api,%s,\"%s\"\n", tag, class_name.get()); 1243 } 1244 1245 1246 void Logger::ApiEntryCall(const char* name) { 1247 if (!log_->IsEnabled() || !FLAG_log_api) return; 1248 ApiEvent("api,%s\n", name); 1249 } 1250 1251 1252 void Logger::NewEvent(const char* name, void* object, size_t size) { 1253 if (!log_->IsEnabled() || !FLAG_log) return; 1254 Log::MessageBuilder msg(log_); 1255 msg.Append("new,%s,0x%" V8PRIxPTR ",%u\n", name, object, 1256 static_cast<unsigned int>(size)); 1257 msg.WriteToLogFile(); 1258 } 1259 1260 1261 void Logger::DeleteEvent(const char* name, void* object) { 1262 if (!log_->IsEnabled() || !FLAG_log) return; 1263 Log::MessageBuilder msg(log_); 1264 msg.Append("delete,%s,0x%" V8PRIxPTR "\n", name, object); 1265 msg.WriteToLogFile(); 1266 } 1267 1268 1269 void Logger::NewEventStatic(const char* name, void* object, size_t size) { 1270 Isolate::Current()->logger()->NewEvent(name, object, size); 1271 } 1272 1273 1274 void Logger::DeleteEventStatic(const char* name, void* object) { 1275 Isolate::Current()->logger()->DeleteEvent(name, object); 1276 } 1277 1278 1279 void Logger::CallbackEventInternal(const char* prefix, Name* name, 1280 Address entry_point) { 1281 if (!FLAG_log_code || !log_->IsEnabled()) return; 1282 Log::MessageBuilder msg(log_); 1283 msg.Append("%s,%s,-2,", 1284 kLogEventsNames[CODE_CREATION_EVENT], 1285 kLogEventsNames[CALLBACK_TAG]); 1286 msg.AppendAddress(entry_point); 1287 if (name->IsString()) { 1288 SmartArrayPointer<char> str = 1289 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1290 msg.Append(",1,\"%s%s\"", prefix, str.get()); 1291 } else { 1292 Symbol* symbol = Symbol::cast(name); 1293 if (symbol->name()->IsUndefined()) { 1294 msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash()); 1295 } else { 1296 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString( 1297 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1298 msg.Append(",1,symbol(\"%s\" hash %x)", prefix, str.get(), 1299 symbol->Hash()); 1300 } 1301 } 1302 msg.Append('\n'); 1303 msg.WriteToLogFile(); 1304 } 1305 1306 1307 void Logger::CallbackEvent(Name* name, Address entry_point) { 1308 PROFILER_LOG(CallbackEvent(name, entry_point)); 1309 CallbackEventInternal("", name, entry_point); 1310 } 1311 1312 1313 void Logger::GetterCallbackEvent(Name* name, Address entry_point) { 1314 PROFILER_LOG(GetterCallbackEvent(name, entry_point)); 1315 CallbackEventInternal("get ", name, entry_point); 1316 } 1317 1318 1319 void Logger::SetterCallbackEvent(Name* name, Address entry_point) { 1320 PROFILER_LOG(SetterCallbackEvent(name, entry_point)); 1321 CallbackEventInternal("set ", name, entry_point); 1322 } 1323 1324 1325 static void AppendCodeCreateHeader(Log::MessageBuilder* msg, 1326 Logger::LogEventsAndTags tag, 1327 Code* code) { 1328 ASSERT(msg); 1329 msg->Append("%s,%s,%d,", 1330 kLogEventsNames[Logger::CODE_CREATION_EVENT], 1331 kLogEventsNames[tag], 1332 code->kind()); 1333 msg->AppendAddress(code->address()); 1334 msg->Append(",%d,", code->ExecutableSize()); 1335 } 1336 1337 1338 void Logger::CodeCreateEvent(LogEventsAndTags tag, 1339 Code* code, 1340 const char* comment) { 1341 PROFILER_LOG(CodeCreateEvent(tag, code, comment)); 1342 1343 if (!is_logging_code_events()) return; 1344 CALL_LISTENERS(CodeCreateEvent(tag, code, comment)); 1345 1346 if (!FLAG_log_code || !log_->IsEnabled()) return; 1347 Log::MessageBuilder msg(log_); 1348 AppendCodeCreateHeader(&msg, tag, code); 1349 msg.AppendDoubleQuotedString(comment); 1350 msg.Append('\n'); 1351 msg.WriteToLogFile(); 1352 } 1353 1354 1355 void Logger::CodeCreateEvent(LogEventsAndTags tag, 1356 Code* code, 1357 Name* name) { 1358 PROFILER_LOG(CodeCreateEvent(tag, code, name)); 1359 1360 if (!is_logging_code_events()) return; 1361 CALL_LISTENERS(CodeCreateEvent(tag, code, name)); 1362 1363 if (!FLAG_log_code || !log_->IsEnabled()) return; 1364 Log::MessageBuilder msg(log_); 1365 AppendCodeCreateHeader(&msg, tag, code); 1366 if (name->IsString()) { 1367 msg.Append('"'); 1368 msg.AppendDetailed(String::cast(name), false); 1369 msg.Append('"'); 1370 } else { 1371 msg.AppendSymbolName(Symbol::cast(name)); 1372 } 1373 msg.Append('\n'); 1374 msg.WriteToLogFile(); 1375 } 1376 1377 1378 void Logger::CodeCreateEvent(LogEventsAndTags tag, 1379 Code* code, 1380 SharedFunctionInfo* shared, 1381 CompilationInfo* info, 1382 Name* name) { 1383 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name)); 1384 1385 if (!is_logging_code_events()) return; 1386 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name)); 1387 1388 if (!FLAG_log_code || !log_->IsEnabled()) return; 1389 if (code == isolate_->builtins()->builtin(Builtins::kCompileUnoptimized)) 1390 return; 1391 1392 Log::MessageBuilder msg(log_); 1393 AppendCodeCreateHeader(&msg, tag, code); 1394 if (name->IsString()) { 1395 SmartArrayPointer<char> str = 1396 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1397 msg.Append("\"%s\"", str.get()); 1398 } else { 1399 msg.AppendSymbolName(Symbol::cast(name)); 1400 } 1401 msg.Append(','); 1402 msg.AppendAddress(shared->address()); 1403 msg.Append(",%s", ComputeMarker(code)); 1404 msg.Append('\n'); 1405 msg.WriteToLogFile(); 1406 } 1407 1408 1409 // Although, it is possible to extract source and line from 1410 // the SharedFunctionInfo object, we left it to caller 1411 // to leave logging functions free from heap allocations. 1412 void Logger::CodeCreateEvent(LogEventsAndTags tag, 1413 Code* code, 1414 SharedFunctionInfo* shared, 1415 CompilationInfo* info, 1416 Name* source, int line, int column) { 1417 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line, column)); 1418 1419 if (!is_logging_code_events()) return; 1420 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line, 1421 column)); 1422 1423 if (!FLAG_log_code || !log_->IsEnabled()) return; 1424 Log::MessageBuilder msg(log_); 1425 AppendCodeCreateHeader(&msg, tag, code); 1426 SmartArrayPointer<char> name = 1427 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1428 msg.Append("\"%s ", name.get()); 1429 if (source->IsString()) { 1430 SmartArrayPointer<char> sourcestr = 1431 String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1432 msg.Append("%s", sourcestr.get()); 1433 } else { 1434 msg.AppendSymbolName(Symbol::cast(source)); 1435 } 1436 msg.Append(":%d:%d\",", line, column); 1437 msg.AppendAddress(shared->address()); 1438 msg.Append(",%s", ComputeMarker(code)); 1439 msg.Append('\n'); 1440 msg.WriteToLogFile(); 1441 } 1442 1443 1444 void Logger::CodeCreateEvent(LogEventsAndTags tag, 1445 Code* code, 1446 int args_count) { 1447 PROFILER_LOG(CodeCreateEvent(tag, code, args_count)); 1448 1449 if (!is_logging_code_events()) return; 1450 CALL_LISTENERS(CodeCreateEvent(tag, code, args_count)); 1451 1452 if (!FLAG_log_code || !log_->IsEnabled()) return; 1453 Log::MessageBuilder msg(log_); 1454 AppendCodeCreateHeader(&msg, tag, code); 1455 msg.Append("\"args_count: %d\"", args_count); 1456 msg.Append('\n'); 1457 msg.WriteToLogFile(); 1458 } 1459 1460 1461 void Logger::CodeDisableOptEvent(Code* code, 1462 SharedFunctionInfo* shared) { 1463 PROFILER_LOG(CodeDisableOptEvent(code, shared)); 1464 1465 if (!is_logging_code_events()) return; 1466 CALL_LISTENERS(CodeDisableOptEvent(code, shared)); 1467 1468 if (!FLAG_log_code || !log_->IsEnabled()) return; 1469 Log::MessageBuilder msg(log_); 1470 msg.Append("%s,", kLogEventsNames[CODE_DISABLE_OPT_EVENT]); 1471 SmartArrayPointer<char> name = 1472 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 1473 msg.Append("\"%s\",", name.get()); 1474 msg.Append("\"%s\"\n", GetBailoutReason(shared->DisableOptimizationReason())); 1475 msg.WriteToLogFile(); 1476 } 1477 1478 1479 void Logger::CodeMovingGCEvent() { 1480 PROFILER_LOG(CodeMovingGCEvent()); 1481 1482 if (!is_logging_code_events()) return; 1483 if (!log_->IsEnabled() || !FLAG_ll_prof) return; 1484 CALL_LISTENERS(CodeMovingGCEvent()); 1485 OS::SignalCodeMovingGC(); 1486 } 1487 1488 1489 void Logger::RegExpCodeCreateEvent(Code* code, String* source) { 1490 PROFILER_LOG(RegExpCodeCreateEvent(code, source)); 1491 1492 if (!is_logging_code_events()) return; 1493 CALL_LISTENERS(RegExpCodeCreateEvent(code, source)); 1494 1495 if (!FLAG_log_code || !log_->IsEnabled()) return; 1496 Log::MessageBuilder msg(log_); 1497 AppendCodeCreateHeader(&msg, REG_EXP_TAG, code); 1498 msg.Append('"'); 1499 msg.AppendDetailed(source, false); 1500 msg.Append('"'); 1501 msg.Append('\n'); 1502 msg.WriteToLogFile(); 1503 } 1504 1505 1506 void Logger::CodeMoveEvent(Address from, Address to) { 1507 PROFILER_LOG(CodeMoveEvent(from, to)); 1508 1509 if (!is_logging_code_events()) return; 1510 CALL_LISTENERS(CodeMoveEvent(from, to)); 1511 MoveEventInternal(CODE_MOVE_EVENT, from, to); 1512 } 1513 1514 1515 void Logger::CodeDeleteEvent(Address from) { 1516 PROFILER_LOG(CodeDeleteEvent(from)); 1517 1518 if (!is_logging_code_events()) return; 1519 CALL_LISTENERS(CodeDeleteEvent(from)); 1520 1521 if (!FLAG_log_code || !log_->IsEnabled()) return; 1522 Log::MessageBuilder msg(log_); 1523 msg.Append("%s,", kLogEventsNames[CODE_DELETE_EVENT]); 1524 msg.AppendAddress(from); 1525 msg.Append('\n'); 1526 msg.WriteToLogFile(); 1527 } 1528 1529 1530 void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data, 1531 int pc_offset, 1532 int position) { 1533 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data, 1534 pc_offset, 1535 position, 1536 JitCodeEvent::POSITION)); 1537 } 1538 1539 1540 void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data, 1541 int pc_offset, 1542 int position) { 1543 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data, 1544 pc_offset, 1545 position, 1546 JitCodeEvent::STATEMENT_POSITION)); 1547 } 1548 1549 1550 void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) { 1551 if (jit_logger_ != NULL) { 1552 pos_recorder->AttachJITHandlerData(jit_logger_->StartCodePosInfoEvent()); 1553 } 1554 } 1555 1556 1557 void Logger::CodeEndLinePosInfoRecordEvent(Code* code, 1558 void* jit_handler_data) { 1559 JIT_LOG(EndCodePosInfoEvent(code, jit_handler_data)); 1560 } 1561 1562 1563 void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) { 1564 if (code_name == NULL) return; // Not a code object. 1565 Log::MessageBuilder msg(log_); 1566 msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos); 1567 msg.AppendDoubleQuotedString(code_name); 1568 msg.Append("\n"); 1569 msg.WriteToLogFile(); 1570 } 1571 1572 1573 void Logger::SnapshotPositionEvent(Address addr, int pos) { 1574 if (!log_->IsEnabled()) return; 1575 LL_LOG(SnapshotPositionEvent(addr, pos)); 1576 if (!FLAG_log_snapshot_positions) return; 1577 Log::MessageBuilder msg(log_); 1578 msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]); 1579 msg.AppendAddress(addr); 1580 msg.Append(",%d", pos); 1581 msg.Append('\n'); 1582 msg.WriteToLogFile(); 1583 } 1584 1585 1586 void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) { 1587 PROFILER_LOG(SharedFunctionInfoMoveEvent(from, to)); 1588 1589 if (!is_logging_code_events()) return; 1590 MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to); 1591 } 1592 1593 1594 void Logger::MoveEventInternal(LogEventsAndTags event, 1595 Address from, 1596 Address to) { 1597 if (!FLAG_log_code || !log_->IsEnabled()) return; 1598 Log::MessageBuilder msg(log_); 1599 msg.Append("%s,", kLogEventsNames[event]); 1600 msg.AppendAddress(from); 1601 msg.Append(','); 1602 msg.AppendAddress(to); 1603 msg.Append('\n'); 1604 msg.WriteToLogFile(); 1605 } 1606 1607 1608 void Logger::ResourceEvent(const char* name, const char* tag) { 1609 if (!log_->IsEnabled() || !FLAG_log) return; 1610 Log::MessageBuilder msg(log_); 1611 msg.Append("%s,%s,", name, tag); 1612 1613 uint32_t sec, usec; 1614 if (OS::GetUserTime(&sec, &usec) != -1) { 1615 msg.Append("%d,%d,", sec, usec); 1616 } 1617 msg.Append("%.0f", OS::TimeCurrentMillis()); 1618 1619 msg.Append('\n'); 1620 msg.WriteToLogFile(); 1621 } 1622 1623 1624 void Logger::SuspectReadEvent(Name* name, Object* obj) { 1625 if (!log_->IsEnabled() || !FLAG_log_suspect) return; 1626 Log::MessageBuilder msg(log_); 1627 String* class_name = obj->IsJSObject() 1628 ? JSObject::cast(obj)->class_name() 1629 : isolate_->heap()->empty_string(); 1630 msg.Append("suspect-read,"); 1631 msg.Append(class_name); 1632 msg.Append(','); 1633 if (name->IsString()) { 1634 msg.Append('"'); 1635 msg.Append(String::cast(name)); 1636 msg.Append('"'); 1637 } else { 1638 msg.AppendSymbolName(Symbol::cast(name)); 1639 } 1640 msg.Append('\n'); 1641 msg.WriteToLogFile(); 1642 } 1643 1644 1645 void Logger::HeapSampleBeginEvent(const char* space, const char* kind) { 1646 if (!log_->IsEnabled() || !FLAG_log_gc) return; 1647 Log::MessageBuilder msg(log_); 1648 // Using non-relative system time in order to be able to synchronize with 1649 // external memory profiling events (e.g. DOM memory size). 1650 msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n", 1651 space, kind, OS::TimeCurrentMillis()); 1652 msg.WriteToLogFile(); 1653 } 1654 1655 1656 void Logger::HeapSampleEndEvent(const char* space, const char* kind) { 1657 if (!log_->IsEnabled() || !FLAG_log_gc) return; 1658 Log::MessageBuilder msg(log_); 1659 msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind); 1660 msg.WriteToLogFile(); 1661 } 1662 1663 1664 void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) { 1665 if (!log_->IsEnabled() || !FLAG_log_gc) return; 1666 Log::MessageBuilder msg(log_); 1667 msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes); 1668 msg.WriteToLogFile(); 1669 } 1670 1671 1672 void Logger::DebugTag(const char* call_site_tag) { 1673 if (!log_->IsEnabled() || !FLAG_log) return; 1674 Log::MessageBuilder msg(log_); 1675 msg.Append("debug-tag,%s\n", call_site_tag); 1676 msg.WriteToLogFile(); 1677 } 1678 1679 1680 void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) { 1681 if (!log_->IsEnabled() || !FLAG_log) return; 1682 StringBuilder s(parameter.length() + 1); 1683 for (int i = 0; i < parameter.length(); ++i) { 1684 s.AddCharacter(static_cast<char>(parameter[i])); 1685 } 1686 char* parameter_string = s.Finalize(); 1687 Log::MessageBuilder msg(log_); 1688 msg.Append("debug-queue-event,%s,%15.3f,%s\n", 1689 event_type, 1690 OS::TimeCurrentMillis(), 1691 parameter_string); 1692 DeleteArray(parameter_string); 1693 msg.WriteToLogFile(); 1694 } 1695 1696 1697 void Logger::TickEvent(TickSample* sample, bool overflow) { 1698 if (!log_->IsEnabled() || !FLAG_prof) return; 1699 Log::MessageBuilder msg(log_); 1700 msg.Append("%s,", kLogEventsNames[TICK_EVENT]); 1701 msg.AppendAddress(sample->pc); 1702 msg.Append(",%ld", static_cast<int>(timer_.Elapsed().InMicroseconds())); 1703 if (sample->has_external_callback) { 1704 msg.Append(",1,"); 1705 msg.AppendAddress(sample->external_callback); 1706 } else { 1707 msg.Append(",0,"); 1708 msg.AppendAddress(sample->tos); 1709 } 1710 msg.Append(",%d", static_cast<int>(sample->state)); 1711 if (overflow) { 1712 msg.Append(",overflow"); 1713 } 1714 for (int i = 0; i < sample->frames_count; ++i) { 1715 msg.Append(','); 1716 msg.AppendAddress(sample->stack[i]); 1717 } 1718 msg.Append('\n'); 1719 msg.WriteToLogFile(); 1720 } 1721 1722 1723 void Logger::StopProfiler() { 1724 if (!log_->IsEnabled()) return; 1725 if (profiler_ != NULL) { 1726 profiler_->pause(); 1727 is_logging_ = false; 1728 } 1729 } 1730 1731 1732 // This function can be called when Log's mutex is acquired, 1733 // either from main or Profiler's thread. 1734 void Logger::LogFailure() { 1735 StopProfiler(); 1736 } 1737 1738 1739 class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor { 1740 public: 1741 EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis, 1742 Handle<Code>* code_objects, 1743 int* count) 1744 : sfis_(sfis), code_objects_(code_objects), count_(count) { } 1745 1746 virtual void EnterContext(Context* context) {} 1747 virtual void LeaveContext(Context* context) {} 1748 1749 virtual void VisitFunction(JSFunction* function) { 1750 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared()); 1751 Object* maybe_script = sfi->script(); 1752 if (maybe_script->IsScript() 1753 && !Script::cast(maybe_script)->HasValidSource()) return; 1754 if (sfis_ != NULL) { 1755 sfis_[*count_] = Handle<SharedFunctionInfo>(sfi); 1756 } 1757 if (code_objects_ != NULL) { 1758 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION); 1759 code_objects_[*count_] = Handle<Code>(function->code()); 1760 } 1761 *count_ = *count_ + 1; 1762 } 1763 1764 private: 1765 Handle<SharedFunctionInfo>* sfis_; 1766 Handle<Code>* code_objects_; 1767 int* count_; 1768 }; 1769 1770 1771 static int EnumerateCompiledFunctions(Heap* heap, 1772 Handle<SharedFunctionInfo>* sfis, 1773 Handle<Code>* code_objects) { 1774 HeapIterator iterator(heap); 1775 DisallowHeapAllocation no_gc; 1776 int compiled_funcs_count = 0; 1777 1778 // Iterate the heap to find shared function info objects and record 1779 // the unoptimized code for them. 1780 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { 1781 if (!obj->IsSharedFunctionInfo()) continue; 1782 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj); 1783 if (sfi->is_compiled() 1784 && (!sfi->script()->IsScript() 1785 || Script::cast(sfi->script())->HasValidSource())) { 1786 if (sfis != NULL) { 1787 sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi); 1788 } 1789 if (code_objects != NULL) { 1790 code_objects[compiled_funcs_count] = Handle<Code>(sfi->code()); 1791 } 1792 ++compiled_funcs_count; 1793 } 1794 } 1795 1796 // Iterate all optimized functions in all contexts. 1797 EnumerateOptimizedFunctionsVisitor visitor(sfis, 1798 code_objects, 1799 &compiled_funcs_count); 1800 Deoptimizer::VisitAllOptimizedFunctions(heap->isolate(), &visitor); 1801 1802 return compiled_funcs_count; 1803 } 1804 1805 1806 void Logger::LogCodeObject(Object* object) { 1807 Code* code_object = Code::cast(object); 1808 LogEventsAndTags tag = Logger::STUB_TAG; 1809 const char* description = "Unknown code from the snapshot"; 1810 switch (code_object->kind()) { 1811 case Code::FUNCTION: 1812 case Code::OPTIMIZED_FUNCTION: 1813 return; // We log this later using LogCompiledFunctions. 1814 case Code::BINARY_OP_IC: 1815 case Code::COMPARE_IC: // fall through 1816 case Code::COMPARE_NIL_IC: // fall through 1817 case Code::TO_BOOLEAN_IC: // fall through 1818 case Code::STUB: 1819 description = 1820 CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true); 1821 if (description == NULL) 1822 description = "A stub from the snapshot"; 1823 tag = Logger::STUB_TAG; 1824 break; 1825 case Code::REGEXP: 1826 description = "Regular expression code"; 1827 tag = Logger::REG_EXP_TAG; 1828 break; 1829 case Code::BUILTIN: 1830 description = "A builtin from the snapshot"; 1831 tag = Logger::BUILTIN_TAG; 1832 break; 1833 case Code::HANDLER: 1834 description = "An IC handler from the snapshot"; 1835 tag = Logger::HANDLER_TAG; 1836 break; 1837 case Code::KEYED_LOAD_IC: 1838 description = "A keyed load IC from the snapshot"; 1839 tag = Logger::KEYED_LOAD_IC_TAG; 1840 break; 1841 case Code::LOAD_IC: 1842 description = "A load IC from the snapshot"; 1843 tag = Logger::LOAD_IC_TAG; 1844 break; 1845 case Code::CALL_IC: 1846 description = "A call IC from the snapshot"; 1847 tag = Logger::CALL_IC_TAG; 1848 break; 1849 case Code::STORE_IC: 1850 description = "A store IC from the snapshot"; 1851 tag = Logger::STORE_IC_TAG; 1852 break; 1853 case Code::KEYED_STORE_IC: 1854 description = "A keyed store IC from the snapshot"; 1855 tag = Logger::KEYED_STORE_IC_TAG; 1856 break; 1857 case Code::NUMBER_OF_KINDS: 1858 break; 1859 } 1860 PROFILE(isolate_, CodeCreateEvent(tag, code_object, description)); 1861 } 1862 1863 1864 void Logger::LogCodeObjects() { 1865 Heap* heap = isolate_->heap(); 1866 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, 1867 "Logger::LogCodeObjects"); 1868 HeapIterator iterator(heap); 1869 DisallowHeapAllocation no_gc; 1870 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { 1871 if (obj->IsCode()) LogCodeObject(obj); 1872 } 1873 } 1874 1875 1876 void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared, 1877 Handle<Code> code) { 1878 Handle<String> func_name(shared->DebugName()); 1879 if (shared->script()->IsScript()) { 1880 Handle<Script> script(Script::cast(shared->script())); 1881 int line_num = Script::GetLineNumber(script, shared->start_position()) + 1; 1882 int column_num = 1883 Script::GetColumnNumber(script, shared->start_position()) + 1; 1884 if (script->name()->IsString()) { 1885 Handle<String> script_name(String::cast(script->name())); 1886 if (line_num > 0) { 1887 PROFILE(isolate_, 1888 CodeCreateEvent( 1889 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script), 1890 *code, *shared, NULL, 1891 *script_name, line_num, column_num)); 1892 } else { 1893 // Can't distinguish eval and script here, so always use Script. 1894 PROFILE(isolate_, 1895 CodeCreateEvent( 1896 Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), 1897 *code, *shared, NULL, *script_name)); 1898 } 1899 } else { 1900 PROFILE(isolate_, 1901 CodeCreateEvent( 1902 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script), 1903 *code, *shared, NULL, 1904 isolate_->heap()->empty_string(), line_num, column_num)); 1905 } 1906 } else if (shared->IsApiFunction()) { 1907 // API function. 1908 FunctionTemplateInfo* fun_data = shared->get_api_func_data(); 1909 Object* raw_call_data = fun_data->call_code(); 1910 if (!raw_call_data->IsUndefined()) { 1911 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data); 1912 Object* callback_obj = call_data->callback(); 1913 Address entry_point = v8::ToCData<Address>(callback_obj); 1914 PROFILE(isolate_, CallbackEvent(*func_name, entry_point)); 1915 } 1916 } else { 1917 PROFILE(isolate_, 1918 CodeCreateEvent( 1919 Logger::LAZY_COMPILE_TAG, *code, *shared, NULL, *func_name)); 1920 } 1921 } 1922 1923 1924 void Logger::LogCompiledFunctions() { 1925 Heap* heap = isolate_->heap(); 1926 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, 1927 "Logger::LogCompiledFunctions"); 1928 HandleScope scope(isolate_); 1929 const int compiled_funcs_count = EnumerateCompiledFunctions(heap, NULL, NULL); 1930 ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count); 1931 ScopedVector< Handle<Code> > code_objects(compiled_funcs_count); 1932 EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start()); 1933 1934 // During iteration, there can be heap allocation due to 1935 // GetScriptLineNumber call. 1936 for (int i = 0; i < compiled_funcs_count; ++i) { 1937 if (code_objects[i].is_identical_to( 1938 isolate_->builtins()->CompileUnoptimized())) 1939 continue; 1940 LogExistingFunction(sfis[i], code_objects[i]); 1941 } 1942 } 1943 1944 1945 void Logger::LogAccessorCallbacks() { 1946 Heap* heap = isolate_->heap(); 1947 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, 1948 "Logger::LogAccessorCallbacks"); 1949 HeapIterator iterator(heap); 1950 DisallowHeapAllocation no_gc; 1951 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { 1952 if (!obj->IsExecutableAccessorInfo()) continue; 1953 ExecutableAccessorInfo* ai = ExecutableAccessorInfo::cast(obj); 1954 if (!ai->name()->IsName()) continue; 1955 Address getter_entry = v8::ToCData<Address>(ai->getter()); 1956 Name* name = Name::cast(ai->name()); 1957 if (getter_entry != 0) { 1958 PROFILE(isolate_, GetterCallbackEvent(name, getter_entry)); 1959 } 1960 Address setter_entry = v8::ToCData<Address>(ai->setter()); 1961 if (setter_entry != 0) { 1962 PROFILE(isolate_, SetterCallbackEvent(name, setter_entry)); 1963 } 1964 } 1965 } 1966 1967 1968 static void AddIsolateIdIfNeeded(Isolate* isolate, StringStream* stream) { 1969 if (FLAG_logfile_per_isolate) stream->Add("isolate-%p-", isolate); 1970 } 1971 1972 1973 static SmartArrayPointer<const char> PrepareLogFileName( 1974 Isolate* isolate, const char* file_name) { 1975 HeapStringAllocator allocator; 1976 StringStream stream(&allocator); 1977 AddIsolateIdIfNeeded(isolate, &stream); 1978 for (const char* p = file_name; *p; p++) { 1979 if (*p == '%') { 1980 p++; 1981 switch (*p) { 1982 case '\0': 1983 // If there's a % at the end of the string we back up 1984 // one character so we can escape the loop properly. 1985 p--; 1986 break; 1987 case 'p': 1988 stream.Add("%d", OS::GetCurrentProcessId()); 1989 break; 1990 case 't': { 1991 // %t expands to the current time in milliseconds. 1992 double time = OS::TimeCurrentMillis(); 1993 stream.Add("%.0f", FmtElm(time)); 1994 break; 1995 } 1996 case '%': 1997 // %% expands (contracts really) to %. 1998 stream.Put('%'); 1999 break; 2000 default: 2001 // All other %'s expand to themselves. 2002 stream.Put('%'); 2003 stream.Put(*p); 2004 break; 2005 } 2006 } else { 2007 stream.Put(*p); 2008 } 2009 } 2010 return SmartArrayPointer<const char>(stream.ToCString()); 2011 } 2012 2013 2014 bool Logger::SetUp(Isolate* isolate) { 2015 // Tests and EnsureInitialize() can call this twice in a row. It's harmless. 2016 if (is_initialized_) return true; 2017 is_initialized_ = true; 2018 2019 // --ll-prof implies --log-code and --log-snapshot-positions. 2020 if (FLAG_ll_prof) { 2021 FLAG_log_snapshot_positions = true; 2022 } 2023 2024 SmartArrayPointer<const char> log_file_name = 2025 PrepareLogFileName(isolate, FLAG_logfile); 2026 log_->Initialize(log_file_name.get()); 2027 2028 2029 if (FLAG_perf_basic_prof) { 2030 perf_basic_logger_ = new PerfBasicLogger(); 2031 addCodeEventListener(perf_basic_logger_); 2032 } 2033 2034 if (FLAG_perf_jit_prof) { 2035 perf_jit_logger_ = new PerfJitLogger(); 2036 addCodeEventListener(perf_jit_logger_); 2037 } 2038 2039 if (FLAG_ll_prof) { 2040 ll_logger_ = new LowLevelLogger(log_file_name.get()); 2041 addCodeEventListener(ll_logger_); 2042 } 2043 2044 ticker_ = new Ticker(isolate, kSamplingIntervalMs); 2045 2046 if (Log::InitLogAtStart()) { 2047 is_logging_ = true; 2048 } 2049 2050 if (FLAG_prof) { 2051 profiler_ = new Profiler(isolate); 2052 is_logging_ = true; 2053 profiler_->Engage(); 2054 } 2055 2056 if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start(); 2057 2058 return true; 2059 } 2060 2061 2062 void Logger::SetCodeEventHandler(uint32_t options, 2063 JitCodeEventHandler event_handler) { 2064 if (jit_logger_) { 2065 removeCodeEventListener(jit_logger_); 2066 delete jit_logger_; 2067 jit_logger_ = NULL; 2068 } 2069 2070 if (event_handler) { 2071 jit_logger_ = new JitLogger(event_handler); 2072 addCodeEventListener(jit_logger_); 2073 if (options & kJitCodeEventEnumExisting) { 2074 HandleScope scope(isolate_); 2075 LogCodeObjects(); 2076 LogCompiledFunctions(); 2077 } 2078 } 2079 } 2080 2081 2082 Sampler* Logger::sampler() { 2083 return ticker_; 2084 } 2085 2086 2087 FILE* Logger::TearDown() { 2088 if (!is_initialized_) return NULL; 2089 is_initialized_ = false; 2090 2091 // Stop the profiler before closing the file. 2092 if (profiler_ != NULL) { 2093 profiler_->Disengage(); 2094 delete profiler_; 2095 profiler_ = NULL; 2096 } 2097 2098 delete ticker_; 2099 ticker_ = NULL; 2100 2101 if (perf_basic_logger_) { 2102 removeCodeEventListener(perf_basic_logger_); 2103 delete perf_basic_logger_; 2104 perf_basic_logger_ = NULL; 2105 } 2106 2107 if (perf_jit_logger_) { 2108 removeCodeEventListener(perf_jit_logger_); 2109 delete perf_jit_logger_; 2110 perf_jit_logger_ = NULL; 2111 } 2112 2113 if (ll_logger_) { 2114 removeCodeEventListener(ll_logger_); 2115 delete ll_logger_; 2116 ll_logger_ = NULL; 2117 } 2118 2119 if (jit_logger_) { 2120 removeCodeEventListener(jit_logger_); 2121 delete jit_logger_; 2122 jit_logger_ = NULL; 2123 } 2124 2125 return log_->Close(); 2126 } 2127 2128 } } // namespace v8::internal 2129