PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/deps/v8/src/log.cc

http://github.com/joyent/node
C++ | 1956 lines | 1498 code | 358 blank | 100 comment | 261 complexity | d0ea5ff634311a618dac8e3012109ea2 MD5 | raw file
Possible License(s): 0BSD, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, ISC, Apache-2.0, MIT, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. // Copyright 2011 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. #include <stdarg.h>
  28. #include "v8.h"
  29. #include "bootstrapper.h"
  30. #include "code-stubs.h"
  31. #include "cpu-profiler.h"
  32. #include "deoptimizer.h"
  33. #include "global-handles.h"
  34. #include "log.h"
  35. #include "log-utils.h"
  36. #include "macro-assembler.h"
  37. #include "platform.h"
  38. #include "runtime-profiler.h"
  39. #include "serialize.h"
  40. #include "string-stream.h"
  41. #include "vm-state-inl.h"
  42. namespace v8 {
  43. namespace internal {
  44. #define DECLARE_EVENT(ignore1, name) name,
  45. static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
  46. LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
  47. };
  48. #undef DECLARE_EVENT
  49. #define CALL_LISTENERS(Call) \
  50. for (int i = 0; i < listeners_.length(); ++i) { \
  51. listeners_[i]->Call; \
  52. }
  53. #define PROFILER_LOG(Call) \
  54. do { \
  55. CpuProfiler* cpu_profiler = isolate_->cpu_profiler(); \
  56. if (cpu_profiler->is_profiling()) { \
  57. cpu_profiler->Call; \
  58. } \
  59. } while (false);
  60. // ComputeMarker must only be used when SharedFunctionInfo is known.
  61. static const char* ComputeMarker(Code* code) {
  62. switch (code->kind()) {
  63. case Code::FUNCTION: return code->optimizable() ? "~" : "";
  64. case Code::OPTIMIZED_FUNCTION: return "*";
  65. default: return "";
  66. }
  67. }
  68. class CodeEventLogger::NameBuffer {
  69. public:
  70. NameBuffer() { Reset(); }
  71. void Reset() {
  72. utf8_pos_ = 0;
  73. }
  74. void Init(Logger::LogEventsAndTags tag) {
  75. Reset();
  76. AppendBytes(kLogEventsNames[tag]);
  77. AppendByte(':');
  78. }
  79. void AppendName(Name* name) {
  80. if (name->IsString()) {
  81. AppendString(String::cast(name));
  82. } else {
  83. Symbol* symbol = Symbol::cast(name);
  84. AppendBytes("symbol(");
  85. if (!symbol->name()->IsUndefined()) {
  86. AppendBytes("\"");
  87. AppendString(String::cast(symbol->name()));
  88. AppendBytes("\" ");
  89. }
  90. AppendBytes("hash ");
  91. AppendHex(symbol->Hash());
  92. AppendByte(')');
  93. }
  94. }
  95. void AppendString(String* str) {
  96. if (str == NULL) return;
  97. int uc16_length = Min(str->length(), kUtf16BufferSize);
  98. String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
  99. int previous = unibrow::Utf16::kNoPreviousCharacter;
  100. for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
  101. uc16 c = utf16_buffer[i];
  102. if (c <= unibrow::Utf8::kMaxOneByteChar) {
  103. utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
  104. } else {
  105. int char_length = unibrow::Utf8::Length(c, previous);
  106. if (utf8_pos_ + char_length > kUtf8BufferSize) break;
  107. unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
  108. utf8_pos_ += char_length;
  109. }
  110. previous = c;
  111. }
  112. }
  113. void AppendBytes(const char* bytes, int size) {
  114. size = Min(size, kUtf8BufferSize - utf8_pos_);
  115. OS::MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
  116. utf8_pos_ += size;
  117. }
  118. void AppendBytes(const char* bytes) {
  119. AppendBytes(bytes, StrLength(bytes));
  120. }
  121. void AppendByte(char c) {
  122. if (utf8_pos_ >= kUtf8BufferSize) return;
  123. utf8_buffer_[utf8_pos_++] = c;
  124. }
  125. void AppendInt(int n) {
  126. Vector<char> buffer(utf8_buffer_ + utf8_pos_,
  127. kUtf8BufferSize - utf8_pos_);
  128. int size = OS::SNPrintF(buffer, "%d", n);
  129. if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
  130. utf8_pos_ += size;
  131. }
  132. }
  133. void AppendHex(uint32_t n) {
  134. Vector<char> buffer(utf8_buffer_ + utf8_pos_,
  135. kUtf8BufferSize - utf8_pos_);
  136. int size = OS::SNPrintF(buffer, "%x", n);
  137. if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
  138. utf8_pos_ += size;
  139. }
  140. }
  141. const char* get() { return utf8_buffer_; }
  142. int size() const { return utf8_pos_; }
  143. private:
  144. static const int kUtf8BufferSize = 512;
  145. static const int kUtf16BufferSize = 128;
  146. int utf8_pos_;
  147. char utf8_buffer_[kUtf8BufferSize];
  148. uc16 utf16_buffer[kUtf16BufferSize];
  149. };
  150. CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { }
  151. CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
  152. void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
  153. Code* code,
  154. const char* comment) {
  155. name_buffer_->Init(tag);
  156. name_buffer_->AppendBytes(comment);
  157. LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
  158. }
  159. void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
  160. Code* code,
  161. Name* name) {
  162. name_buffer_->Init(tag);
  163. name_buffer_->AppendName(name);
  164. LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
  165. }
  166. void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
  167. Code* code,
  168. SharedFunctionInfo* shared,
  169. CompilationInfo* info,
  170. Name* name) {
  171. name_buffer_->Init(tag);
  172. name_buffer_->AppendBytes(ComputeMarker(code));
  173. name_buffer_->AppendName(name);
  174. LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
  175. }
  176. void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
  177. Code* code,
  178. SharedFunctionInfo* shared,
  179. CompilationInfo* info,
  180. Name* source, int line) {
  181. name_buffer_->Init(tag);
  182. name_buffer_->AppendBytes(ComputeMarker(code));
  183. name_buffer_->AppendString(shared->DebugName());
  184. name_buffer_->AppendByte(' ');
  185. if (source->IsString()) {
  186. name_buffer_->AppendString(String::cast(source));
  187. } else {
  188. name_buffer_->AppendBytes("symbol(hash ");
  189. name_buffer_->AppendHex(Name::cast(source)->Hash());
  190. name_buffer_->AppendByte(')');
  191. }
  192. name_buffer_->AppendByte(':');
  193. name_buffer_->AppendInt(line);
  194. LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
  195. }
  196. void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
  197. Code* code,
  198. int args_count) {
  199. name_buffer_->Init(tag);
  200. name_buffer_->AppendInt(args_count);
  201. LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
  202. }
  203. void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) {
  204. name_buffer_->Init(Logger::REG_EXP_TAG);
  205. name_buffer_->AppendString(source);
  206. LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
  207. }
  208. // Low-level logging support.
  209. #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
  210. class LowLevelLogger : public CodeEventLogger {
  211. public:
  212. explicit LowLevelLogger(const char* file_name);
  213. virtual ~LowLevelLogger();
  214. virtual void CodeMoveEvent(Address from, Address to);
  215. virtual void CodeDeleteEvent(Address from);
  216. virtual void SnapshotPositionEvent(Address addr, int pos);
  217. virtual void CodeMovingGCEvent();
  218. private:
  219. virtual void LogRecordedBuffer(Code* code,
  220. SharedFunctionInfo* shared,
  221. const char* name,
  222. int length);
  223. // Low-level profiling event structures.
  224. struct CodeCreateStruct {
  225. static const char kTag = 'C';
  226. int32_t name_size;
  227. Address code_address;
  228. int32_t code_size;
  229. };
  230. struct CodeMoveStruct {
  231. static const char kTag = 'M';
  232. Address from_address;
  233. Address to_address;
  234. };
  235. struct CodeDeleteStruct {
  236. static const char kTag = 'D';
  237. Address address;
  238. };
  239. struct SnapshotPositionStruct {
  240. static const char kTag = 'P';
  241. Address address;
  242. int32_t position;
  243. };
  244. static const char kCodeMovingGCTag = 'G';
  245. // Extension added to V8 log file name to get the low-level log name.
  246. static const char kLogExt[];
  247. // File buffer size of the low-level log. We don't use the default to
  248. // minimize the associated overhead.
  249. static const int kLogBufferSize = 2 * MB;
  250. void LogCodeInfo();
  251. void LogWriteBytes(const char* bytes, int size);
  252. template <typename T>
  253. void LogWriteStruct(const T& s) {
  254. char tag = T::kTag;
  255. LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
  256. LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
  257. }
  258. FILE* ll_output_handle_;
  259. };
  260. const char LowLevelLogger::kLogExt[] = ".ll";
  261. LowLevelLogger::LowLevelLogger(const char* name)
  262. : ll_output_handle_(NULL) {
  263. // Open the low-level log file.
  264. size_t len = strlen(name);
  265. ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
  266. OS::MemCopy(ll_name.start(), name, len);
  267. OS::MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt));
  268. ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
  269. setvbuf(ll_output_handle_, NULL, _IOFBF, kLogBufferSize);
  270. LogCodeInfo();
  271. }
  272. LowLevelLogger::~LowLevelLogger() {
  273. fclose(ll_output_handle_);
  274. ll_output_handle_ = NULL;
  275. }
  276. void LowLevelLogger::LogCodeInfo() {
  277. #if V8_TARGET_ARCH_IA32
  278. const char arch[] = "ia32";
  279. #elif V8_TARGET_ARCH_X64
  280. const char arch[] = "x64";
  281. #elif V8_TARGET_ARCH_ARM
  282. const char arch[] = "arm";
  283. #elif V8_TARGET_ARCH_MIPS
  284. const char arch[] = "mips";
  285. #else
  286. const char arch[] = "unknown";
  287. #endif
  288. LogWriteBytes(arch, sizeof(arch));
  289. }
  290. void LowLevelLogger::LogRecordedBuffer(Code* code,
  291. SharedFunctionInfo*,
  292. const char* name,
  293. int length) {
  294. CodeCreateStruct event;
  295. event.name_size = length;
  296. event.code_address = code->instruction_start();
  297. ASSERT(event.code_address == code->address() + Code::kHeaderSize);
  298. event.code_size = code->instruction_size();
  299. LogWriteStruct(event);
  300. LogWriteBytes(name, length);
  301. LogWriteBytes(
  302. reinterpret_cast<const char*>(code->instruction_start()),
  303. code->instruction_size());
  304. }
  305. void LowLevelLogger::CodeMoveEvent(Address from, Address to) {
  306. CodeMoveStruct event;
  307. event.from_address = from + Code::kHeaderSize;
  308. event.to_address = to + Code::kHeaderSize;
  309. LogWriteStruct(event);
  310. }
  311. void LowLevelLogger::CodeDeleteEvent(Address from) {
  312. CodeDeleteStruct event;
  313. event.address = from + Code::kHeaderSize;
  314. LogWriteStruct(event);
  315. }
  316. void LowLevelLogger::SnapshotPositionEvent(Address addr, int pos) {
  317. SnapshotPositionStruct event;
  318. event.address = addr + Code::kHeaderSize;
  319. event.position = pos;
  320. LogWriteStruct(event);
  321. }
  322. void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
  323. size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
  324. ASSERT(static_cast<size_t>(size) == rv);
  325. USE(rv);
  326. }
  327. void LowLevelLogger::CodeMovingGCEvent() {
  328. const char tag = kCodeMovingGCTag;
  329. LogWriteBytes(&tag, sizeof(tag));
  330. }
  331. #define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
  332. class JitLogger : public CodeEventLogger {
  333. public:
  334. explicit JitLogger(JitCodeEventHandler code_event_handler);
  335. virtual void CodeMoveEvent(Address from, Address to);
  336. virtual void CodeDeleteEvent(Address from);
  337. virtual void AddCodeLinePosInfoEvent(
  338. void* jit_handler_data,
  339. int pc_offset,
  340. int position,
  341. JitCodeEvent::PositionType position_type);
  342. void* StartCodePosInfoEvent();
  343. void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
  344. private:
  345. virtual void LogRecordedBuffer(Code* code,
  346. SharedFunctionInfo* shared,
  347. const char* name,
  348. int length);
  349. JitCodeEventHandler code_event_handler_;
  350. };
  351. JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
  352. : code_event_handler_(code_event_handler) {
  353. }
  354. void JitLogger::LogRecordedBuffer(Code* code,
  355. SharedFunctionInfo* shared,
  356. const char* name,
  357. int length) {
  358. JitCodeEvent event;
  359. memset(&event, 0, sizeof(event));
  360. event.type = JitCodeEvent::CODE_ADDED;
  361. event.code_start = code->instruction_start();
  362. event.code_len = code->instruction_size();
  363. Handle<Script> script_handle;
  364. if (shared && shared->script()->IsScript()) {
  365. script_handle = Handle<Script>(Script::cast(shared->script()));
  366. }
  367. event.script = ToApiHandle<v8::Script>(script_handle);
  368. event.name.str = name;
  369. event.name.len = length;
  370. code_event_handler_(&event);
  371. }
  372. void JitLogger::CodeMoveEvent(Address from, Address to) {
  373. Code* from_code = Code::cast(HeapObject::FromAddress(from));
  374. JitCodeEvent event;
  375. event.type = JitCodeEvent::CODE_MOVED;
  376. event.code_start = from_code->instruction_start();
  377. event.code_len = from_code->instruction_size();
  378. // Calculate the header size.
  379. const size_t header_size =
  380. from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
  381. // Calculate the new start address of the instructions.
  382. event.new_code_start =
  383. reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
  384. code_event_handler_(&event);
  385. }
  386. void JitLogger::CodeDeleteEvent(Address from) {
  387. Code* from_code = Code::cast(HeapObject::FromAddress(from));
  388. JitCodeEvent event;
  389. event.type = JitCodeEvent::CODE_REMOVED;
  390. event.code_start = from_code->instruction_start();
  391. event.code_len = from_code->instruction_size();
  392. code_event_handler_(&event);
  393. }
  394. void JitLogger::AddCodeLinePosInfoEvent(
  395. void* jit_handler_data,
  396. int pc_offset,
  397. int position,
  398. JitCodeEvent::PositionType position_type) {
  399. JitCodeEvent event;
  400. memset(&event, 0, sizeof(event));
  401. event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
  402. event.user_data = jit_handler_data;
  403. event.line_info.offset = pc_offset;
  404. event.line_info.pos = position;
  405. event.line_info.position_type = position_type;
  406. code_event_handler_(&event);
  407. }
  408. void* JitLogger::StartCodePosInfoEvent() {
  409. JitCodeEvent event;
  410. memset(&event, 0, sizeof(event));
  411. event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
  412. code_event_handler_(&event);
  413. return event.user_data;
  414. }
  415. void JitLogger::EndCodePosInfoEvent(Code* code, void* jit_handler_data) {
  416. JitCodeEvent event;
  417. memset(&event, 0, sizeof(event));
  418. event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
  419. event.code_start = code->instruction_start();
  420. event.user_data = jit_handler_data;
  421. code_event_handler_(&event);
  422. }
  423. // The Profiler samples pc and sp values for the main thread.
  424. // Each sample is appended to a circular buffer.
  425. // An independent thread removes data and writes it to the log.
  426. // This design minimizes the time spent in the sampler.
  427. //
  428. class Profiler: public Thread {
  429. public:
  430. explicit Profiler(Isolate* isolate);
  431. void Engage();
  432. void Disengage();
  433. // Inserts collected profiling data into buffer.
  434. void Insert(TickSample* sample) {
  435. if (paused_)
  436. return;
  437. if (Succ(head_) == tail_) {
  438. overflow_ = true;
  439. } else {
  440. buffer_[head_] = *sample;
  441. head_ = Succ(head_);
  442. buffer_semaphore_->Signal(); // Tell we have an element.
  443. }
  444. }
  445. // Waits for a signal and removes profiling data.
  446. bool Remove(TickSample* sample) {
  447. buffer_semaphore_->Wait(); // Wait for an element.
  448. *sample = buffer_[tail_];
  449. bool result = overflow_;
  450. tail_ = Succ(tail_);
  451. overflow_ = false;
  452. return result;
  453. }
  454. void Run();
  455. // Pause and Resume TickSample data collection.
  456. bool paused() const { return paused_; }
  457. void pause() { paused_ = true; }
  458. void resume() { paused_ = false; }
  459. private:
  460. // Returns the next index in the cyclic buffer.
  461. int Succ(int index) { return (index + 1) % kBufferSize; }
  462. Isolate* isolate_;
  463. // Cyclic buffer for communicating profiling samples
  464. // between the signal handler and the worker thread.
  465. static const int kBufferSize = 128;
  466. TickSample buffer_[kBufferSize]; // Buffer storage.
  467. int head_; // Index to the buffer head.
  468. int tail_; // Index to the buffer tail.
  469. bool overflow_; // Tell whether a buffer overflow has occurred.
  470. Semaphore* buffer_semaphore_; // Sempahore used for buffer synchronization.
  471. // Tells whether profiler is engaged, that is, processing thread is stated.
  472. bool engaged_;
  473. // Tells whether worker thread should continue running.
  474. bool running_;
  475. // Tells whether we are currently recording tick samples.
  476. bool paused_;
  477. };
  478. //
  479. // Ticker used to provide ticks to the profiler and the sliding state
  480. // window.
  481. //
  482. class Ticker: public Sampler {
  483. public:
  484. Ticker(Isolate* isolate, int interval):
  485. Sampler(isolate, interval),
  486. profiler_(NULL) {}
  487. ~Ticker() { if (IsActive()) Stop(); }
  488. virtual void Tick(TickSample* sample) {
  489. if (profiler_) profiler_->Insert(sample);
  490. }
  491. void SetProfiler(Profiler* profiler) {
  492. ASSERT(profiler_ == NULL);
  493. profiler_ = profiler;
  494. IncreaseProfilingDepth();
  495. if (!FLAG_prof_lazy && !IsActive()) Start();
  496. }
  497. void ClearProfiler() {
  498. DecreaseProfilingDepth();
  499. profiler_ = NULL;
  500. if (IsActive()) Stop();
  501. }
  502. private:
  503. Profiler* profiler_;
  504. };
  505. //
  506. // Profiler implementation.
  507. //
  508. Profiler::Profiler(Isolate* isolate)
  509. : Thread("v8:Profiler"),
  510. isolate_(isolate),
  511. head_(0),
  512. tail_(0),
  513. overflow_(false),
  514. buffer_semaphore_(OS::CreateSemaphore(0)),
  515. engaged_(false),
  516. running_(false),
  517. paused_(false) {
  518. }
  519. void Profiler::Engage() {
  520. if (engaged_) return;
  521. engaged_ = true;
  522. OS::LogSharedLibraryAddresses();
  523. // Start thread processing the profiler buffer.
  524. running_ = true;
  525. Start();
  526. // Register to get ticks.
  527. Logger* logger = isolate_->logger();
  528. logger->ticker_->SetProfiler(this);
  529. logger->ProfilerBeginEvent();
  530. }
  531. void Profiler::Disengage() {
  532. if (!engaged_) return;
  533. // Stop receiving ticks.
  534. isolate_->logger()->ticker_->ClearProfiler();
  535. // Terminate the worker thread by setting running_ to false,
  536. // inserting a fake element in the queue and then wait for
  537. // the thread to terminate.
  538. running_ = false;
  539. TickSample sample;
  540. // Reset 'paused_' flag, otherwise semaphore may not be signalled.
  541. resume();
  542. Insert(&sample);
  543. Join();
  544. LOG(ISOLATE, UncheckedStringEvent("profiler", "end"));
  545. }
  546. void Profiler::Run() {
  547. TickSample sample;
  548. bool overflow = Remove(&sample);
  549. while (running_) {
  550. LOG(isolate_, TickEvent(&sample, overflow));
  551. overflow = Remove(&sample);
  552. }
  553. }
  554. //
  555. // Logger class implementation.
  556. //
  557. Logger::Logger(Isolate* isolate)
  558. : isolate_(isolate),
  559. ticker_(NULL),
  560. profiler_(NULL),
  561. log_events_(NULL),
  562. logging_nesting_(0),
  563. cpu_profiler_nesting_(0),
  564. log_(new Log(this)),
  565. ll_logger_(NULL),
  566. jit_logger_(NULL),
  567. listeners_(5),
  568. is_initialized_(false),
  569. epoch_(0) {
  570. }
  571. Logger::~Logger() {
  572. delete log_;
  573. }
  574. void Logger::addCodeEventListener(CodeEventListener* listener) {
  575. ASSERT(!hasCodeEventListener(listener));
  576. listeners_.Add(listener);
  577. }
  578. void Logger::removeCodeEventListener(CodeEventListener* listener) {
  579. ASSERT(hasCodeEventListener(listener));
  580. listeners_.RemoveElement(listener);
  581. }
  582. bool Logger::hasCodeEventListener(CodeEventListener* listener) {
  583. return listeners_.Contains(listener);
  584. }
  585. void Logger::ProfilerBeginEvent() {
  586. if (!log_->IsEnabled()) return;
  587. Log::MessageBuilder msg(log_);
  588. msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
  589. msg.WriteToLogFile();
  590. }
  591. void Logger::StringEvent(const char* name, const char* value) {
  592. if (FLAG_log) UncheckedStringEvent(name, value);
  593. }
  594. void Logger::UncheckedStringEvent(const char* name, const char* value) {
  595. if (!log_->IsEnabled()) return;
  596. Log::MessageBuilder msg(log_);
  597. msg.Append("%s,\"%s\"\n", name, value);
  598. msg.WriteToLogFile();
  599. }
  600. void Logger::IntEvent(const char* name, int value) {
  601. if (FLAG_log) UncheckedIntEvent(name, value);
  602. }
  603. void Logger::IntPtrTEvent(const char* name, intptr_t value) {
  604. if (FLAG_log) UncheckedIntPtrTEvent(name, value);
  605. }
  606. void Logger::UncheckedIntEvent(const char* name, int value) {
  607. if (!log_->IsEnabled()) return;
  608. Log::MessageBuilder msg(log_);
  609. msg.Append("%s,%d\n", name, value);
  610. msg.WriteToLogFile();
  611. }
  612. void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
  613. if (!log_->IsEnabled()) return;
  614. Log::MessageBuilder msg(log_);
  615. msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value);
  616. msg.WriteToLogFile();
  617. }
  618. void Logger::HandleEvent(const char* name, Object** location) {
  619. if (!log_->IsEnabled() || !FLAG_log_handles) return;
  620. Log::MessageBuilder msg(log_);
  621. msg.Append("%s,0x%" V8PRIxPTR "\n", name, location);
  622. msg.WriteToLogFile();
  623. }
  624. // ApiEvent is private so all the calls come from the Logger class. It is the
  625. // caller's responsibility to ensure that log is enabled and that
  626. // FLAG_log_api is true.
  627. void Logger::ApiEvent(const char* format, ...) {
  628. ASSERT(log_->IsEnabled() && FLAG_log_api);
  629. Log::MessageBuilder msg(log_);
  630. va_list ap;
  631. va_start(ap, format);
  632. msg.AppendVA(format, ap);
  633. va_end(ap);
  634. msg.WriteToLogFile();
  635. }
  636. void Logger::ApiNamedSecurityCheck(Object* key) {
  637. if (!log_->IsEnabled() || !FLAG_log_api) return;
  638. if (key->IsString()) {
  639. SmartArrayPointer<char> str =
  640. String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  641. ApiEvent("api,check-security,\"%s\"\n", *str);
  642. } else if (key->IsSymbol()) {
  643. Symbol* symbol = Symbol::cast(key);
  644. if (symbol->name()->IsUndefined()) {
  645. ApiEvent("api,check-security,symbol(hash %x)\n",
  646. Symbol::cast(key)->Hash());
  647. } else {
  648. SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
  649. DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  650. ApiEvent("api,check-security,symbol(\"%s\" hash %x)\n",
  651. *str,
  652. Symbol::cast(key)->Hash());
  653. }
  654. } else if (key->IsUndefined()) {
  655. ApiEvent("api,check-security,undefined\n");
  656. } else {
  657. ApiEvent("api,check-security,['no-name']\n");
  658. }
  659. }
  660. void Logger::SharedLibraryEvent(const char* library_path,
  661. uintptr_t start,
  662. uintptr_t end) {
  663. if (!log_->IsEnabled() || !FLAG_prof) return;
  664. Log::MessageBuilder msg(log_);
  665. msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
  666. library_path,
  667. start,
  668. end);
  669. msg.WriteToLogFile();
  670. }
  671. void Logger::SharedLibraryEvent(const wchar_t* library_path,
  672. uintptr_t start,
  673. uintptr_t end) {
  674. if (!log_->IsEnabled() || !FLAG_prof) return;
  675. Log::MessageBuilder msg(log_);
  676. msg.Append("shared-library,\"%ls\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
  677. library_path,
  678. start,
  679. end);
  680. msg.WriteToLogFile();
  681. }
  682. void Logger::CodeDeoptEvent(Code* code) {
  683. if (!log_->IsEnabled()) return;
  684. ASSERT(FLAG_log_internal_timer_events);
  685. Log::MessageBuilder msg(log_);
  686. int since_epoch = static_cast<int>(OS::Ticks() - epoch_);
  687. msg.Append("code-deopt,%ld,%d\n", since_epoch, code->CodeSize());
  688. msg.WriteToLogFile();
  689. }
  690. void Logger::TimerEvent(StartEnd se, const char* name) {
  691. if (!log_->IsEnabled()) return;
  692. ASSERT(FLAG_log_internal_timer_events);
  693. Log::MessageBuilder msg(log_);
  694. int since_epoch = static_cast<int>(OS::Ticks() - epoch_);
  695. const char* format = (se == START) ? "timer-event-start,\"%s\",%ld\n"
  696. : "timer-event-end,\"%s\",%ld\n";
  697. msg.Append(format, name, since_epoch);
  698. msg.WriteToLogFile();
  699. }
  700. void Logger::EnterExternal(Isolate* isolate) {
  701. LOG(isolate, TimerEvent(START, TimerEventScope::v8_external));
  702. ASSERT(isolate->current_vm_state() == JS);
  703. isolate->set_current_vm_state(EXTERNAL);
  704. }
  705. void Logger::LeaveExternal(Isolate* isolate) {
  706. LOG(isolate, TimerEvent(END, TimerEventScope::v8_external));
  707. ASSERT(isolate->current_vm_state() == EXTERNAL);
  708. isolate->set_current_vm_state(JS);
  709. }
  710. void Logger::TimerEventScope::LogTimerEvent(StartEnd se) {
  711. LOG(isolate_, TimerEvent(se, name_));
  712. }
  713. const char* Logger::TimerEventScope::v8_recompile_synchronous =
  714. "V8.RecompileSynchronous";
  715. const char* Logger::TimerEventScope::v8_recompile_parallel =
  716. "V8.RecompileParallel";
  717. const char* Logger::TimerEventScope::v8_compile_full_code =
  718. "V8.CompileFullCode";
  719. const char* Logger::TimerEventScope::v8_execute = "V8.Execute";
  720. const char* Logger::TimerEventScope::v8_external = "V8.External";
  721. void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
  722. // Prints "/" + re.source + "/" +
  723. // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
  724. Log::MessageBuilder msg(log_);
  725. Handle<Object> source = GetProperty(regexp, "source");
  726. if (!source->IsString()) {
  727. msg.Append("no source");
  728. return;
  729. }
  730. switch (regexp->TypeTag()) {
  731. case JSRegExp::ATOM:
  732. msg.Append('a');
  733. break;
  734. default:
  735. break;
  736. }
  737. msg.Append('/');
  738. msg.AppendDetailed(*Handle<String>::cast(source), false);
  739. msg.Append('/');
  740. // global flag
  741. Handle<Object> global = GetProperty(regexp, "global");
  742. if (global->IsTrue()) {
  743. msg.Append('g');
  744. }
  745. // ignorecase flag
  746. Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase");
  747. if (ignorecase->IsTrue()) {
  748. msg.Append('i');
  749. }
  750. // multiline flag
  751. Handle<Object> multiline = GetProperty(regexp, "multiline");
  752. if (multiline->IsTrue()) {
  753. msg.Append('m');
  754. }
  755. msg.WriteToLogFile();
  756. }
  757. void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
  758. if (!log_->IsEnabled() || !FLAG_log_regexp) return;
  759. Log::MessageBuilder msg(log_);
  760. msg.Append("regexp-compile,");
  761. LogRegExpSource(regexp);
  762. msg.Append(in_cache ? ",hit\n" : ",miss\n");
  763. msg.WriteToLogFile();
  764. }
  765. void Logger::LogRuntime(Vector<const char> format,
  766. JSArray* args) {
  767. if (!log_->IsEnabled() || !FLAG_log_runtime) return;
  768. HandleScope scope(isolate_);
  769. Log::MessageBuilder msg(log_);
  770. for (int i = 0; i < format.length(); i++) {
  771. char c = format[i];
  772. if (c == '%' && i <= format.length() - 2) {
  773. i++;
  774. ASSERT('0' <= format[i] && format[i] <= '9');
  775. MaybeObject* maybe = args->GetElement(format[i] - '0');
  776. Object* obj;
  777. if (!maybe->ToObject(&obj)) {
  778. msg.Append("<exception>");
  779. continue;
  780. }
  781. i++;
  782. switch (format[i]) {
  783. case 's':
  784. msg.AppendDetailed(String::cast(obj), false);
  785. break;
  786. case 'S':
  787. msg.AppendDetailed(String::cast(obj), true);
  788. break;
  789. case 'r':
  790. Logger::LogRegExpSource(Handle<JSRegExp>(JSRegExp::cast(obj)));
  791. break;
  792. case 'x':
  793. msg.Append("0x%x", Smi::cast(obj)->value());
  794. break;
  795. case 'i':
  796. msg.Append("%i", Smi::cast(obj)->value());
  797. break;
  798. default:
  799. UNREACHABLE();
  800. }
  801. } else {
  802. msg.Append(c);
  803. }
  804. }
  805. msg.Append('\n');
  806. msg.WriteToLogFile();
  807. }
  808. void Logger::ApiIndexedSecurityCheck(uint32_t index) {
  809. if (!log_->IsEnabled() || !FLAG_log_api) return;
  810. ApiEvent("api,check-security,%u\n", index);
  811. }
  812. void Logger::ApiNamedPropertyAccess(const char* tag,
  813. JSObject* holder,
  814. Object* name) {
  815. ASSERT(name->IsName());
  816. if (!log_->IsEnabled() || !FLAG_log_api) return;
  817. String* class_name_obj = holder->class_name();
  818. SmartArrayPointer<char> class_name =
  819. class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  820. if (name->IsString()) {
  821. SmartArrayPointer<char> property_name =
  822. String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  823. ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
  824. } else {
  825. Symbol* symbol = Symbol::cast(name);
  826. uint32_t hash = symbol->Hash();
  827. if (symbol->name()->IsUndefined()) {
  828. ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash);
  829. } else {
  830. SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
  831. DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  832. ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)\n",
  833. tag, *class_name, *str, hash);
  834. }
  835. }
  836. }
  837. void Logger::ApiIndexedPropertyAccess(const char* tag,
  838. JSObject* holder,
  839. uint32_t index) {
  840. if (!log_->IsEnabled() || !FLAG_log_api) return;
  841. String* class_name_obj = holder->class_name();
  842. SmartArrayPointer<char> class_name =
  843. class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  844. ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
  845. }
  846. void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
  847. if (!log_->IsEnabled() || !FLAG_log_api) return;
  848. String* class_name_obj = object->class_name();
  849. SmartArrayPointer<char> class_name =
  850. class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  851. ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
  852. }
  853. void Logger::ApiEntryCall(const char* name) {
  854. if (!log_->IsEnabled() || !FLAG_log_api) return;
  855. ApiEvent("api,%s\n", name);
  856. }
  857. void Logger::NewEvent(const char* name, void* object, size_t size) {
  858. if (!log_->IsEnabled() || !FLAG_log) return;
  859. Log::MessageBuilder msg(log_);
  860. msg.Append("new,%s,0x%" V8PRIxPTR ",%u\n", name, object,
  861. static_cast<unsigned int>(size));
  862. msg.WriteToLogFile();
  863. }
  864. void Logger::DeleteEvent(const char* name, void* object) {
  865. if (!log_->IsEnabled() || !FLAG_log) return;
  866. Log::MessageBuilder msg(log_);
  867. msg.Append("delete,%s,0x%" V8PRIxPTR "\n", name, object);
  868. msg.WriteToLogFile();
  869. }
  870. void Logger::NewEventStatic(const char* name, void* object, size_t size) {
  871. Isolate::Current()->logger()->NewEvent(name, object, size);
  872. }
  873. void Logger::DeleteEventStatic(const char* name, void* object) {
  874. Isolate::Current()->logger()->DeleteEvent(name, object);
  875. }
  876. void Logger::CallbackEventInternal(const char* prefix, Name* name,
  877. Address entry_point) {
  878. if (!FLAG_log_code || !log_->IsEnabled()) return;
  879. Log::MessageBuilder msg(log_);
  880. msg.Append("%s,%s,-2,",
  881. kLogEventsNames[CODE_CREATION_EVENT],
  882. kLogEventsNames[CALLBACK_TAG]);
  883. msg.AppendAddress(entry_point);
  884. if (name->IsString()) {
  885. SmartArrayPointer<char> str =
  886. String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  887. msg.Append(",1,\"%s%s\"", prefix, *str);
  888. } else {
  889. Symbol* symbol = Symbol::cast(name);
  890. if (symbol->name()->IsUndefined()) {
  891. msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
  892. } else {
  893. SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
  894. DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  895. msg.Append(",1,symbol(\"%s\" hash %x)", prefix, *str, symbol->Hash());
  896. }
  897. }
  898. msg.Append('\n');
  899. msg.WriteToLogFile();
  900. }
  901. void Logger::CallbackEvent(Name* name, Address entry_point) {
  902. PROFILER_LOG(CallbackEvent(name, entry_point));
  903. CallbackEventInternal("", name, entry_point);
  904. }
  905. void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
  906. PROFILER_LOG(GetterCallbackEvent(name, entry_point));
  907. CallbackEventInternal("get ", name, entry_point);
  908. }
  909. void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
  910. PROFILER_LOG(SetterCallbackEvent(name, entry_point));
  911. CallbackEventInternal("set ", name, entry_point);
  912. }
  913. static void AppendCodeCreateHeader(Log::MessageBuilder* msg,
  914. Logger::LogEventsAndTags tag,
  915. Code* code) {
  916. ASSERT(msg);
  917. msg->Append("%s,%s,%d,",
  918. kLogEventsNames[Logger::CODE_CREATION_EVENT],
  919. kLogEventsNames[tag],
  920. code->kind());
  921. msg->AppendAddress(code->address());
  922. msg->Append(",%d,", code->ExecutableSize());
  923. }
  924. void Logger::CodeCreateEvent(LogEventsAndTags tag,
  925. Code* code,
  926. const char* comment) {
  927. PROFILER_LOG(CodeCreateEvent(tag, code, comment));
  928. if (!is_logging_code_events()) return;
  929. CALL_LISTENERS(CodeCreateEvent(tag, code, comment));
  930. if (!FLAG_log_code || !log_->IsEnabled()) return;
  931. Log::MessageBuilder msg(log_);
  932. AppendCodeCreateHeader(&msg, tag, code);
  933. msg.AppendDoubleQuotedString(comment);
  934. msg.Append('\n');
  935. msg.WriteToLogFile();
  936. }
  937. void Logger::CodeCreateEvent(LogEventsAndTags tag,
  938. Code* code,
  939. Name* name) {
  940. PROFILER_LOG(CodeCreateEvent(tag, code, name));
  941. if (!is_logging_code_events()) return;
  942. CALL_LISTENERS(CodeCreateEvent(tag, code, name));
  943. if (!FLAG_log_code || !log_->IsEnabled()) return;
  944. Log::MessageBuilder msg(log_);
  945. AppendCodeCreateHeader(&msg, tag, code);
  946. if (name->IsString()) {
  947. msg.Append('"');
  948. msg.AppendDetailed(String::cast(name), false);
  949. msg.Append('"');
  950. } else {
  951. msg.AppendSymbolName(Symbol::cast(name));
  952. }
  953. msg.Append('\n');
  954. msg.WriteToLogFile();
  955. }
  956. void Logger::CodeCreateEvent(LogEventsAndTags tag,
  957. Code* code,
  958. SharedFunctionInfo* shared,
  959. CompilationInfo* info,
  960. Name* name) {
  961. PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name));
  962. if (!is_logging_code_events()) return;
  963. CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name));
  964. if (!FLAG_log_code || !log_->IsEnabled()) return;
  965. if (code == isolate_->builtins()->builtin(
  966. Builtins::kLazyCompile))
  967. return;
  968. Log::MessageBuilder msg(log_);
  969. AppendCodeCreateHeader(&msg, tag, code);
  970. if (name->IsString()) {
  971. SmartArrayPointer<char> str =
  972. String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  973. msg.Append("\"%s\"", *str);
  974. } else {
  975. msg.AppendSymbolName(Symbol::cast(name));
  976. }
  977. msg.Append(',');
  978. msg.AppendAddress(shared->address());
  979. msg.Append(",%s", ComputeMarker(code));
  980. msg.Append('\n');
  981. msg.WriteToLogFile();
  982. }
  983. // Although, it is possible to extract source and line from
  984. // the SharedFunctionInfo object, we left it to caller
  985. // to leave logging functions free from heap allocations.
  986. void Logger::CodeCreateEvent(LogEventsAndTags tag,
  987. Code* code,
  988. SharedFunctionInfo* shared,
  989. CompilationInfo* info,
  990. Name* source, int line) {
  991. PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line));
  992. if (!is_logging_code_events()) return;
  993. CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line));
  994. if (!FLAG_log_code || !log_->IsEnabled()) return;
  995. Log::MessageBuilder msg(log_);
  996. AppendCodeCreateHeader(&msg, tag, code);
  997. SmartArrayPointer<char> name =
  998. shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  999. msg.Append("\"%s ", *name);
  1000. if (source->IsString()) {
  1001. SmartArrayPointer<char> sourcestr =
  1002. String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  1003. msg.Append("%s", *sourcestr);
  1004. } else {
  1005. msg.AppendSymbolName(Symbol::cast(source));
  1006. }
  1007. msg.Append(":%d\",", line);
  1008. msg.AppendAddress(shared->address());
  1009. msg.Append(",%s", ComputeMarker(code));
  1010. msg.Append('\n');
  1011. msg.WriteToLogFile();
  1012. }
  1013. void Logger::CodeCreateEvent(LogEventsAndTags tag,
  1014. Code* code,
  1015. int args_count) {
  1016. PROFILER_LOG(CodeCreateEvent(tag, code, args_count));
  1017. if (!is_logging_code_events()) return;
  1018. CALL_LISTENERS(CodeCreateEvent(tag, code, args_count));
  1019. if (!FLAG_log_code || !log_->IsEnabled()) return;
  1020. Log::MessageBuilder msg(log_);
  1021. AppendCodeCreateHeader(&msg, tag, code);
  1022. msg.Append("\"args_count: %d\"", args_count);
  1023. msg.Append('\n');
  1024. msg.WriteToLogFile();
  1025. }
  1026. void Logger::CodeMovingGCEvent() {
  1027. PROFILER_LOG(CodeMovingGCEvent());
  1028. if (!is_logging_code_events()) return;
  1029. if (!log_->IsEnabled() || !FLAG_ll_prof) return;
  1030. CALL_LISTENERS(CodeMovingGCEvent());
  1031. OS::SignalCodeMovingGC();
  1032. }
  1033. void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
  1034. PROFILER_LOG(RegExpCodeCreateEvent(code, source));
  1035. if (!is_logging_code_events()) return;
  1036. CALL_LISTENERS(RegExpCodeCreateEvent(code, source));
  1037. if (!FLAG_log_code || !log_->IsEnabled()) return;
  1038. Log::MessageBuilder msg(log_);
  1039. AppendCodeCreateHeader(&msg, REG_EXP_TAG, code);
  1040. msg.Append('"');
  1041. msg.AppendDetailed(source, false);
  1042. msg.Append('"');
  1043. msg.Append('\n');
  1044. msg.WriteToLogFile();
  1045. }
  1046. void Logger::CodeMoveEvent(Address from, Address to) {
  1047. PROFILER_LOG(CodeMoveEvent(from, to));
  1048. if (!is_logging_code_events()) return;
  1049. CALL_LISTENERS(CodeMoveEvent(from, to));
  1050. MoveEventInternal(CODE_MOVE_EVENT, from, to);
  1051. }
  1052. void Logger::CodeDeleteEvent(Address from) {
  1053. PROFILER_LOG(CodeDeleteEvent(from));
  1054. if (!is_logging_code_events()) return;
  1055. CALL_LISTENERS(CodeDeleteEvent(from));
  1056. if (!FLAG_log_code || !log_->IsEnabled()) return;
  1057. Log::MessageBuilder msg(log_);
  1058. msg.Append("%s,", kLogEventsNames[CODE_DELETE_EVENT]);
  1059. msg.AppendAddress(from);
  1060. msg.Append('\n');
  1061. msg.WriteToLogFile();
  1062. }
  1063. void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
  1064. int pc_offset,
  1065. int position) {
  1066. JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
  1067. pc_offset,
  1068. position,
  1069. JitCodeEvent::POSITION));
  1070. }
  1071. void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
  1072. int pc_offset,
  1073. int position) {
  1074. JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
  1075. pc_offset,
  1076. position,
  1077. JitCodeEvent::STATEMENT_POSITION));
  1078. }
  1079. void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
  1080. if (jit_logger_ != NULL) {
  1081. pos_recorder->AttachJITHandlerData(jit_logger_->StartCodePosInfoEvent());
  1082. }
  1083. }
  1084. void Logger::CodeEndLinePosInfoRecordEvent(Code* code,
  1085. void* jit_handler_data) {
  1086. JIT_LOG(EndCodePosInfoEvent(code, jit_handler_data));
  1087. }
  1088. void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
  1089. if (code_name == NULL) return; // Not a code object.
  1090. Log::MessageBuilder msg(log_);
  1091. msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
  1092. msg.AppendDoubleQuotedString(code_name);
  1093. msg.Append("\n");
  1094. msg.WriteToLogFile();
  1095. }
  1096. void Logger::SnapshotPositionEvent(Address addr, int pos) {
  1097. if (!log_->IsEnabled()) return;
  1098. LL_LOG(SnapshotPositionEvent(addr, pos));
  1099. if (!FLAG_log_snapshot_positions) return;
  1100. Log::MessageBuilder msg(log_);
  1101. msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
  1102. msg.AppendAddress(addr);
  1103. msg.Append(",%d", pos);
  1104. msg.Append('\n');
  1105. msg.WriteToLogFile();
  1106. }
  1107. void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
  1108. PROFILER_LOG(SharedFunctionInfoMoveEvent(from, to));
  1109. if (!is_logging_code_events()) return;
  1110. MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
  1111. }
  1112. void Logger::MoveEventInternal(LogEventsAndTags event,
  1113. Address from,
  1114. Address to) {
  1115. if (!FLAG_log_code || !log_->IsEnabled()) return;
  1116. Log::MessageBuilder msg(log_);
  1117. msg.Append("%s,", kLogEventsNames[event]);
  1118. msg.AppendAddress(from);
  1119. msg.Append(',');
  1120. msg.AppendAddress(to);
  1121. msg.Append('\n');
  1122. msg.WriteToLogFile();
  1123. }
  1124. void Logger::ResourceEvent(const char* name, const char* tag) {
  1125. if (!log_->IsEnabled() || !FLAG_log) return;
  1126. Log::MessageBuilder msg(log_);
  1127. msg.Append("%s,%s,", name, tag);
  1128. uint32_t sec, usec;
  1129. if (OS::GetUserTime(&sec, &usec) != -1) {
  1130. msg.Append("%d,%d,", sec, usec);
  1131. }
  1132. msg.Append("%.0f", OS::TimeCurrentMillis());
  1133. msg.Append('\n');
  1134. msg.WriteToLogFile();
  1135. }
  1136. void Logger::SuspectReadEvent(Name* name, Object* obj) {
  1137. if (!log_->IsEnabled() || !FLAG_log_suspect) return;
  1138. Log::MessageBuilder msg(log_);
  1139. String* class_name = obj->IsJSObject()
  1140. ? JSObject::cast(obj)->class_name()
  1141. : isolate_->heap()->empty_string();
  1142. msg.Append("suspect-read,");
  1143. msg.Append(class_name);
  1144. msg.Append(',');
  1145. if (name->IsString()) {
  1146. msg.Append('"');
  1147. msg.Append(String::cast(name));
  1148. msg.Append('"');
  1149. } else {
  1150. msg.AppendSymbolName(Symbol::cast(name));
  1151. }
  1152. msg.Append('\n');
  1153. msg.WriteToLogFile();
  1154. }
  1155. void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
  1156. if (!log_->IsEnabled() || !FLAG_log_gc) return;
  1157. Log::MessageBuilder msg(log_);
  1158. // Using non-relative system time in order to be able to synchronize with
  1159. // external memory profiling events (e.g. DOM memory size).
  1160. msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
  1161. space, kind, OS::TimeCurrentMillis());
  1162. msg.WriteToLogFile();
  1163. }
  1164. void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
  1165. if (!log_->IsEnabled() || !FLAG_log_gc) return;
  1166. Log::MessageBuilder msg(log_);
  1167. msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind);
  1168. msg.WriteToLogFile();
  1169. }
  1170. void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
  1171. if (!log_->IsEnabled() || !FLAG_log_gc) return;
  1172. Log::MessageBuilder msg(log_);
  1173. msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes);
  1174. msg.WriteToLogFile();
  1175. }
  1176. void Logger::DebugTag(const char* call_site_tag) {
  1177. if (!log_->IsEnabled() || !FLAG_log) return;
  1178. Log::MessageBuilder msg(log_);
  1179. msg.Append("debug-tag,%s\n", call_site_tag);
  1180. msg.WriteToLogFile();
  1181. }
  1182. void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
  1183. if (!log_->IsEnabled() || !FLAG_log) return;
  1184. StringBuilder s(parameter.length() + 1);
  1185. for (int i = 0; i < parameter.length(); ++i) {
  1186. s.AddCharacter(static_cast<char>(parameter[i]));
  1187. }
  1188. char* parameter_string = s.Finalize();
  1189. Log::MessageBuilder msg(log_);
  1190. msg.Append("debug-queue-event,%s,%15.3f,%s\n",
  1191. event_type,
  1192. OS::TimeCurrentMillis(),
  1193. parameter_string);
  1194. DeleteArray(parameter_string);
  1195. msg.WriteToLogFile();
  1196. }
  1197. void Logger::TickEvent(TickSample* sample, bool overflow) {
  1198. if (!log_->IsEnabled() || !FLAG_prof) return;
  1199. Log::MessageBuilder msg(log_);
  1200. msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
  1201. msg.AppendAddress(sample->pc);
  1202. msg.Append(",%ld", static_cast<int>(OS::Ticks() - epoch_));
  1203. if (sample->has_external_callback) {
  1204. msg.Append(",1,");
  1205. msg.AppendAddress(sample->external_callback);
  1206. } else {
  1207. msg.Append(",0,");
  1208. msg.AppendAddress(sample->tos);
  1209. }
  1210. msg.Append(",%d", static_cast<int>(sample->state));
  1211. if (overflow) {
  1212. msg.Append(",overflow");
  1213. }
  1214. for (int i = 0; i < sample->frames_count; ++i) {
  1215. msg.Append(',');
  1216. msg.AppendAddress(sample->stack[i]);
  1217. }
  1218. msg.Append('\n');
  1219. msg.WriteToLogFile();
  1220. }
  1221. bool Logger::IsProfilerPaused() {
  1222. return profiler_ == NULL || profiler_->paused();
  1223. }
  1224. void Logger::PauseProfiler() {
  1225. if (!log_->IsEnabled()) return;
  1226. if (profiler_ != NULL) {
  1227. // It is OK to have negative nesting.
  1228. if (--cpu_profiler_nesting_ == 0) {
  1229. profiler_->pause();
  1230. if (FLAG_prof_lazy) {
  1231. ticker_->Stop();
  1232. FLAG_log_code = false;
  1233. LOG(ISOLATE, UncheckedStringEvent("profiler", "pause"));
  1234. }
  1235. --logging_nesting_;
  1236. }
  1237. }
  1238. }
  1239. void Logger::ResumeProfiler() {
  1240. if (!log_->IsEnabled()) return;
  1241. if (profiler_ != NULL) {
  1242. if (cpu_profiler_nesting_++ == 0) {
  1243. ++logging_nesting_;
  1244. if (FLAG_prof_lazy) {
  1245. profiler_->Engage();
  1246. LOG(ISOLATE, UncheckedStringEvent("profiler", "resume"));
  1247. FLAG_log_code = true;
  1248. LogCompiledFunctions();
  1249. LogAccessorCallbacks();
  1250. if (!ticker_->IsActive()) ticker_->Start();
  1251. }
  1252. profiler_->resume();
  1253. }
  1254. }
  1255. }
  1256. // This function can be called when Log's mutex is acquired,
  1257. // either from main or Profiler's thread.
  1258. void Logger::LogFailure() {
  1259. PauseProfiler();
  1260. }
  1261. class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
  1262. public:
  1263. EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
  1264. Handle<Code>* code_objects,
  1265. int* count)
  1266. : sfis_(sfis), code_objects_(code_objects), count_(count) { }
  1267. virtual void EnterContext(Context* context) {}
  1268. virtual void LeaveContext(Context* context) {}
  1269. virtual void VisitFunction(JSFunction* function) {
  1270. SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
  1271. Object* maybe_script = sfi->script();
  1272. if (maybe_script->IsScript()
  1273. && !Script::cast(maybe_script)->HasValidSource()) return;
  1274. if (sfis_ != NULL) {
  1275. sfis_[*count_] = Handle<SharedFunctionInfo>(sfi);
  1276. }
  1277. if (code_objects_ != NULL) {
  1278. ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
  1279. code_objects_[*count_] = Handle<Code>(function->code());
  1280. }
  1281. *count_ = *count_ + 1;
  1282. }
  1283. private:
  1284. Handle<SharedFunctionInfo>* sfis_;
  1285. Handle<Code>* code_objects_;
  1286. int* count_;
  1287. };
  1288. static int EnumerateCompiledFunctions(Heap* heap,
  1289. Handle<SharedFunctionInfo>* sfis,
  1290. Handle<Code>* code_objects) {
  1291. HeapIterator iterator(heap);
  1292. DisallowHeapAllocation no_gc;
  1293. int compiled_funcs_count = 0;
  1294. // Iterate the heap to find shared function info objects and record
  1295. // the unoptimized code for them.
  1296. for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
  1297. if (!obj->IsSharedFunctionInfo()) continue;
  1298. SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
  1299. if (sfi->is_compiled()
  1300. && (!sfi->script()->IsScript()
  1301. || Script::cast(sfi->script())->HasValidSource())) {
  1302. if (sfis != NULL) {
  1303. sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
  1304. }
  1305. if (code_objects != NULL) {
  1306. code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
  1307. }
  1308. ++compiled_funcs_count;
  1309. }
  1310. }
  1311. // Iterate all optimized functions in all contexts.
  1312. EnumerateOptimizedFunctionsVisitor visitor(sfis,
  1313. code_objects,
  1314. &compiled_funcs_count);
  1315. Deoptimizer::VisitAllOptimizedFunctions(heap->isolate(), &visitor);
  1316. return compiled_funcs_count;
  1317. }
  1318. void Logger::LogCodeObject(Object* object) {
  1319. Code* code_object = Code::cast(object);
  1320. LogEventsAndTags tag = Logger::STUB_TAG;
  1321. const char* description = "Unknown code from the snapshot";
  1322. switch (code_object->kind()) {
  1323. case Code::FUNCTION:
  1324. case Code::OPTIMIZED_FUNCTION:
  1325. return; // We log this later using LogCompiledFunctions.
  1326. case Code::BINARY_OP_IC: // fall through
  1327. case Code::COMPARE_IC: // fall through
  1328. case Code::COMPARE_NIL_IC: // fall through
  1329. case Code::TO_BOOLEAN_IC: // fall through
  1330. case Code::STUB:
  1331. description =
  1332. CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
  1333. if (description == NULL)
  1334. description = "A stub from the snapshot";
  1335. tag = Logger::STUB_TAG;
  1336. break;
  1337. case Code::REGEXP:
  1338. description = "Regular expression code";
  1339. tag = Logger::REG_EXP_TAG;
  1340. break;
  1341. case Code::BUILTIN:
  1342. description = "A builtin from the snapshot";
  1343. tag = Logger::BUILTIN_TAG;
  1344. break;
  1345. case Code::KEYED_LOAD_IC:
  1346. description = "A keyed load IC from the snapshot";
  1347. tag = Logger::KEYED_LOAD_IC_TAG;
  1348. break;
  1349. case Code::LOAD_IC:
  1350. description = "A load IC from the snapshot";
  1351. tag = Logger::LOAD_IC_TAG;
  1352. break;
  1353. case Code::STORE_IC:
  1354. description = "A store IC from the snapshot";
  1355. tag = Logger::STORE_IC_TAG;
  1356. break;
  1357. case Code::KEYED_STORE_IC:
  1358. description = "A keyed store IC from the snapshot";
  1359. tag = Logger::KEYED_STORE_IC_TAG;
  1360. break;
  1361. case Code::CALL_IC:
  1362. description = "A call IC from the snapshot";
  1363. tag = Logger::CALL_IC_TAG;
  1364. break;
  1365. case Code::KEYED_CALL_IC:
  1366. description = "A keyed call IC from the snapshot";
  1367. tag = Logger::KEYED_CALL_IC_TAG;
  1368. break;
  1369. case Code::NUMBER_OF_KINDS:
  1370. break;
  1371. }
  1372. PROFIL

Large files files are truncated, but you can click here to view the full file