Line data Source code
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 "src/log.h"
6 :
7 : #include <cstdarg>
8 : #include <memory>
9 : #include <sstream>
10 :
11 : #include "src/api-inl.h"
12 : #include "src/bailout-reason.h"
13 : #include "src/base/platform/platform.h"
14 : #include "src/bootstrapper.h"
15 : #include "src/counters.h"
16 : #include "src/deoptimizer.h"
17 : #include "src/global-handles.h"
18 : #include "src/interpreter/bytecodes.h"
19 : #include "src/interpreter/interpreter.h"
20 : #include "src/libsampler/sampler.h"
21 : #include "src/log-inl.h"
22 : #include "src/macro-assembler.h"
23 : #include "src/memcopy.h"
24 : #include "src/objects/api-callbacks.h"
25 : #include "src/perf-jit.h"
26 : #include "src/profiler/tick-sample.h"
27 : #include "src/runtime-profiler.h"
28 : #include "src/snapshot/embedded-data.h"
29 : #include "src/source-position-table.h"
30 : #include "src/string-stream.h"
31 : #include "src/tracing/tracing-category-observer.h"
32 : #include "src/unicode-inl.h"
33 : #include "src/vm-state-inl.h"
34 : #include "src/wasm/wasm-code-manager.h"
35 : #include "src/wasm/wasm-objects-inl.h"
36 :
37 : #include "src/version.h"
38 :
39 : namespace v8 {
40 : namespace internal {
41 :
42 : #define DECLARE_EVENT(ignore1, name) #name,
43 : static const char* kLogEventsNames[CodeEventListener::NUMBER_OF_LOG_EVENTS] = {
44 : LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)};
45 : #undef DECLARE_EVENT
46 :
47 20826 : static v8::CodeEventType GetCodeEventTypeForTag(
48 : CodeEventListener::LogEventsAndTags tag) {
49 20826 : switch (tag) {
50 : case CodeEventListener::NUMBER_OF_LOG_EVENTS:
51 : #define V(Event, _) case CodeEventListener::Event:
52 : LOG_EVENTS_LIST(V)
53 : #undef V
54 : return v8::CodeEventType::kUnknownType;
55 : #define V(From, To) \
56 : case CodeEventListener::From: \
57 : return v8::CodeEventType::k##To##Type;
58 20700 : TAGS_LIST(V)
59 : #undef V
60 : }
61 : // The execution should never pass here
62 0 : UNREACHABLE();
63 : // NOTE(mmarchini): Workaround to fix a compiler failure on GCC 4.9
64 : return v8::CodeEventType::kUnknownType;
65 : }
66 : #define CALL_CODE_EVENT_HANDLER(Call) \
67 : if (listener_) { \
68 : listener_->Call; \
69 : } else { \
70 : PROFILE(isolate_, Call); \
71 : }
72 :
73 502 : static const char* ComputeMarker(SharedFunctionInfo shared, AbstractCode code) {
74 502 : switch (code->kind()) {
75 : case AbstractCode::INTERPRETED_FUNCTION:
76 386 : return shared->optimization_disabled() ? "" : "~";
77 : case AbstractCode::OPTIMIZED_FUNCTION:
78 : return "*";
79 : default:
80 35 : return "";
81 : }
82 : }
83 :
84 0 : static const char* ComputeMarker(const wasm::WasmCode* code) {
85 0 : switch (code->kind()) {
86 : case wasm::WasmCode::kFunction:
87 0 : return code->is_liftoff() ? "" : "*";
88 : case wasm::WasmCode::kInterpreterEntry:
89 : return "~";
90 : default:
91 : return "";
92 : }
93 : }
94 :
95 : class CodeEventLogger::NameBuffer {
96 : public:
97 : NameBuffer() { Reset(); }
98 :
99 : void Reset() {
100 6002 : utf8_pos_ = 0;
101 : }
102 :
103 5480 : void Init(CodeEventListener::LogEventsAndTags tag) {
104 : Reset();
105 5480 : AppendBytes(kLogEventsNames[tag]);
106 : AppendByte(':');
107 5480 : }
108 :
109 0 : void AppendName(Name name) {
110 0 : if (name->IsString()) {
111 0 : AppendString(String::cast(name));
112 : } else {
113 0 : Symbol symbol = Symbol::cast(name);
114 0 : AppendBytes("symbol(");
115 0 : if (!symbol->name()->IsUndefined()) {
116 0 : AppendBytes("\"");
117 0 : AppendString(String::cast(symbol->name()));
118 0 : AppendBytes("\" ");
119 : }
120 0 : AppendBytes("hash ");
121 0 : AppendHex(symbol->Hash());
122 : AppendByte(')');
123 : }
124 0 : }
125 :
126 604 : void AppendString(String str) {
127 604 : if (str.is_null()) return;
128 604 : int length = 0;
129 : std::unique_ptr<char[]> c_str =
130 604 : str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, &length);
131 1208 : AppendBytes(c_str.get(), length);
132 : }
133 :
134 11564 : void AppendBytes(const char* bytes, int size) {
135 11564 : size = Min(size, kUtf8BufferSize - utf8_pos_);
136 11564 : MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
137 11564 : utf8_pos_ += size;
138 11564 : }
139 :
140 10960 : void AppendBytes(const char* bytes) {
141 10960 : AppendBytes(bytes, StrLength(bytes));
142 10960 : }
143 :
144 : void AppendByte(char c) {
145 6084 : if (utf8_pos_ >= kUtf8BufferSize) return;
146 6060 : utf8_buffer_[utf8_pos_++] = c;
147 : }
148 :
149 302 : void AppendInt(int n) {
150 302 : int space = kUtf8BufferSize - utf8_pos_;
151 314 : if (space <= 0) return;
152 290 : Vector<char> buffer(utf8_buffer_ + utf8_pos_, space);
153 290 : int size = SNPrintF(buffer, "%d", n);
154 290 : if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
155 290 : utf8_pos_ += size;
156 : }
157 : }
158 :
159 0 : void AppendHex(uint32_t n) {
160 0 : int space = kUtf8BufferSize - utf8_pos_;
161 0 : if (space <= 0) return;
162 0 : Vector<char> buffer(utf8_buffer_ + utf8_pos_, space);
163 0 : int size = SNPrintF(buffer, "%x", n);
164 0 : if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
165 0 : utf8_pos_ += size;
166 : }
167 : }
168 :
169 : const char* get() { return utf8_buffer_; }
170 : int size() const { return utf8_pos_; }
171 :
172 : private:
173 : static const int kUtf8BufferSize = 512;
174 : static const int kUtf16BufferSize = kUtf8BufferSize;
175 :
176 : int utf8_pos_;
177 : char utf8_buffer_[kUtf8BufferSize];
178 : };
179 :
180 487 : CodeEventLogger::CodeEventLogger(Isolate* isolate)
181 1044 : : isolate_(isolate), name_buffer_(new NameBuffer) {}
182 :
183 1009 : CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
184 :
185 5178 : void CodeEventLogger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
186 : AbstractCode code, const char* comment) {
187 10356 : name_buffer_->Init(tag);
188 5178 : name_buffer_->AppendBytes(comment);
189 : LogRecordedBuffer(code, SharedFunctionInfo(), name_buffer_->get(),
190 15534 : name_buffer_->size());
191 5178 : }
192 :
193 0 : void CodeEventLogger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
194 : AbstractCode code, Name name) {
195 0 : name_buffer_->Init(tag);
196 0 : name_buffer_->AppendName(name);
197 : LogRecordedBuffer(code, SharedFunctionInfo(), name_buffer_->get(),
198 0 : name_buffer_->size());
199 0 : }
200 :
201 0 : void CodeEventLogger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
202 : AbstractCode code,
203 : SharedFunctionInfo shared, Name name) {
204 0 : name_buffer_->Init(tag);
205 0 : name_buffer_->AppendBytes(ComputeMarker(shared, code));
206 0 : name_buffer_->AppendByte(' ');
207 0 : name_buffer_->AppendName(name);
208 0 : LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
209 0 : }
210 :
211 302 : void CodeEventLogger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
212 : AbstractCode code,
213 : SharedFunctionInfo shared, Name source,
214 : int line, int column) {
215 604 : name_buffer_->Init(tag);
216 302 : name_buffer_->AppendBytes(ComputeMarker(shared, code));
217 302 : name_buffer_->AppendString(shared->DebugName());
218 302 : name_buffer_->AppendByte(' ');
219 302 : if (source->IsString()) {
220 302 : name_buffer_->AppendString(String::cast(source));
221 : } else {
222 0 : name_buffer_->AppendBytes("symbol(hash ");
223 0 : name_buffer_->AppendHex(Name::cast(source)->Hash());
224 0 : name_buffer_->AppendByte(')');
225 : }
226 302 : name_buffer_->AppendByte(':');
227 302 : name_buffer_->AppendInt(line);
228 604 : LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
229 302 : }
230 :
231 0 : void CodeEventLogger::CodeCreateEvent(LogEventsAndTags tag,
232 0 : const wasm::WasmCode* code,
233 : wasm::WasmName name) {
234 0 : name_buffer_->Init(tag);
235 0 : if (name.is_empty()) {
236 0 : name_buffer_->AppendBytes("<wasm-unknown>");
237 : } else {
238 0 : name_buffer_->AppendBytes(name.start(), name.length());
239 : }
240 0 : name_buffer_->AppendByte('-');
241 0 : if (code->IsAnonymous()) {
242 0 : name_buffer_->AppendBytes("<anonymous>");
243 : } else {
244 0 : name_buffer_->AppendInt(code->index());
245 : }
246 0 : LogRecordedBuffer(code, name_buffer_->get(), name_buffer_->size());
247 0 : }
248 :
249 0 : void CodeEventLogger::RegExpCodeCreateEvent(AbstractCode code, String source) {
250 0 : name_buffer_->Init(CodeEventListener::REG_EXP_TAG);
251 0 : name_buffer_->AppendString(source);
252 : LogRecordedBuffer(code, SharedFunctionInfo(), name_buffer_->get(),
253 0 : name_buffer_->size());
254 0 : }
255 :
256 : // Linux perf tool logging support
257 : class PerfBasicLogger : public CodeEventLogger {
258 : public:
259 : explicit PerfBasicLogger(Isolate* isolate);
260 : ~PerfBasicLogger() override;
261 :
262 0 : void CodeMoveEvent(AbstractCode from, AbstractCode to) override {}
263 0 : void CodeDisableOptEvent(AbstractCode code,
264 0 : SharedFunctionInfo shared) override {}
265 :
266 : private:
267 : void LogRecordedBuffer(AbstractCode code, SharedFunctionInfo shared,
268 : const char* name, int length) override;
269 : void LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
270 : int length) override;
271 : void WriteLogRecordedBuffer(uintptr_t address, int size, const char* name,
272 : int name_length);
273 :
274 : // Extension added to V8 log file name to get the low-level log name.
275 : static const char kFilenameFormatString[];
276 : static const int kFilenameBufferPadding;
277 :
278 : FILE* perf_output_handle_;
279 : };
280 :
281 : const char PerfBasicLogger::kFilenameFormatString[] = "/tmp/perf-%d.map";
282 : // Extra space for the PID in the filename
283 : const int PerfBasicLogger::kFilenameBufferPadding = 16;
284 :
285 0 : PerfBasicLogger::PerfBasicLogger(Isolate* isolate)
286 0 : : CodeEventLogger(isolate), perf_output_handle_(nullptr) {
287 : // Open the perf JIT dump file.
288 : int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
289 : ScopedVector<char> perf_dump_name(bufferSize);
290 : int size = SNPrintF(
291 : perf_dump_name,
292 : kFilenameFormatString,
293 0 : base::OS::GetCurrentProcessId());
294 0 : CHECK_NE(size, -1);
295 : perf_output_handle_ =
296 0 : base::OS::FOpen(perf_dump_name.start(), base::OS::LogFileOpenMode);
297 0 : CHECK_NOT_NULL(perf_output_handle_);
298 0 : setvbuf(perf_output_handle_, nullptr, _IOLBF, 0);
299 0 : }
300 :
301 :
302 0 : PerfBasicLogger::~PerfBasicLogger() {
303 0 : fclose(perf_output_handle_);
304 0 : perf_output_handle_ = nullptr;
305 0 : }
306 :
307 0 : void PerfBasicLogger::WriteLogRecordedBuffer(uintptr_t address, int size,
308 : const char* name,
309 : int name_length) {
310 : // Linux perf expects hex literals without a leading 0x, while some
311 : // implementations of printf might prepend one when using the %p format
312 : // for pointers, leading to wrongly formatted JIT symbols maps.
313 : //
314 : // Instead, we use V8PRIxPTR format string and cast pointer to uintpr_t,
315 : // so that we have control over the exact output format.
316 : base::OS::FPrint(perf_output_handle_, "%" V8PRIxPTR " %x %.*s\n", address,
317 0 : size, name_length, name);
318 0 : }
319 :
320 0 : void PerfBasicLogger::LogRecordedBuffer(AbstractCode code, SharedFunctionInfo,
321 : const char* name, int length) {
322 0 : if (FLAG_perf_basic_prof_only_functions &&
323 0 : (code->kind() != AbstractCode::INTERPRETED_FUNCTION &&
324 0 : code->kind() != AbstractCode::BUILTIN &&
325 0 : code->kind() != AbstractCode::OPTIMIZED_FUNCTION)) {
326 0 : return;
327 : }
328 :
329 : WriteLogRecordedBuffer(static_cast<uintptr_t>(code->InstructionStart()),
330 0 : code->InstructionSize(), name, length);
331 : }
332 :
333 0 : void PerfBasicLogger::LogRecordedBuffer(const wasm::WasmCode* code,
334 : const char* name, int length) {
335 : WriteLogRecordedBuffer(static_cast<uintptr_t>(code->instruction_start()),
336 : code->instructions().length(), name, length);
337 0 : }
338 :
339 : // External CodeEventListener
340 20 : ExternalCodeEventListener::ExternalCodeEventListener(Isolate* isolate)
341 20 : : is_listening_(false), isolate_(isolate), code_event_handler_(nullptr) {}
342 :
343 20 : ExternalCodeEventListener::~ExternalCodeEventListener() {
344 20 : if (is_listening_) {
345 20 : StopListening();
346 : }
347 20 : }
348 :
349 20 : void ExternalCodeEventListener::LogExistingCode() {
350 20 : HandleScope scope(isolate_);
351 20 : ExistingCodeLogger logger(isolate_, this);
352 20 : logger.LogCodeObjects();
353 20 : logger.LogCompiledFunctions();
354 20 : }
355 :
356 20 : void ExternalCodeEventListener::StartListening(
357 : CodeEventHandler* code_event_handler) {
358 20 : if (is_listening_ || code_event_handler == nullptr) {
359 20 : return;
360 : }
361 20 : code_event_handler_ = code_event_handler;
362 40 : is_listening_ = isolate_->code_event_dispatcher()->AddListener(this);
363 20 : if (is_listening_) {
364 20 : LogExistingCode();
365 : }
366 : }
367 :
368 20 : void ExternalCodeEventListener::StopListening() {
369 20 : if (!is_listening_) {
370 20 : return;
371 : }
372 :
373 40 : isolate_->code_event_dispatcher()->RemoveListener(this);
374 20 : is_listening_ = false;
375 : }
376 :
377 20706 : void ExternalCodeEventListener::CodeCreateEvent(
378 : CodeEventListener::LogEventsAndTags tag, AbstractCode code,
379 : const char* comment) {
380 : CodeEvent code_event;
381 : code_event.code_start_address =
382 20706 : static_cast<uintptr_t>(code->InstructionStart());
383 20706 : code_event.code_size = static_cast<size_t>(code->InstructionSize());
384 41412 : code_event.function_name = isolate_->factory()->empty_string();
385 20706 : code_event.script_name = isolate_->factory()->empty_string();
386 20706 : code_event.script_line = 0;
387 20706 : code_event.script_column = 0;
388 20706 : code_event.code_type = GetCodeEventTypeForTag(tag);
389 20706 : code_event.comment = comment;
390 :
391 20706 : code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
392 20706 : }
393 :
394 0 : void ExternalCodeEventListener::CodeCreateEvent(
395 : CodeEventListener::LogEventsAndTags tag, AbstractCode code, Name name) {
396 : Handle<String> name_string =
397 0 : Name::ToFunctionName(isolate_, Handle<Name>(name, isolate_))
398 0 : .ToHandleChecked();
399 :
400 : CodeEvent code_event;
401 : code_event.code_start_address =
402 0 : static_cast<uintptr_t>(code->InstructionStart());
403 0 : code_event.code_size = static_cast<size_t>(code->InstructionSize());
404 0 : code_event.function_name = name_string;
405 0 : code_event.script_name = isolate_->factory()->empty_string();
406 0 : code_event.script_line = 0;
407 0 : code_event.script_column = 0;
408 0 : code_event.code_type = GetCodeEventTypeForTag(tag);
409 0 : code_event.comment = "";
410 :
411 0 : code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
412 0 : }
413 :
414 0 : void ExternalCodeEventListener::CodeCreateEvent(
415 : CodeEventListener::LogEventsAndTags tag, AbstractCode code,
416 : SharedFunctionInfo shared, Name name) {
417 : Handle<String> name_string =
418 0 : Name::ToFunctionName(isolate_, Handle<Name>(name, isolate_))
419 0 : .ToHandleChecked();
420 :
421 : CodeEvent code_event;
422 : code_event.code_start_address =
423 0 : static_cast<uintptr_t>(code->InstructionStart());
424 0 : code_event.code_size = static_cast<size_t>(code->InstructionSize());
425 0 : code_event.function_name = name_string;
426 0 : code_event.script_name = isolate_->factory()->empty_string();
427 0 : code_event.script_line = 0;
428 0 : code_event.script_column = 0;
429 0 : code_event.code_type = GetCodeEventTypeForTag(tag);
430 0 : code_event.comment = "";
431 :
432 0 : code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
433 0 : }
434 :
435 120 : void ExternalCodeEventListener::CodeCreateEvent(
436 : CodeEventListener::LogEventsAndTags tag, AbstractCode code,
437 : SharedFunctionInfo shared, Name source, int line, int column) {
438 : Handle<String> name_string =
439 360 : Name::ToFunctionName(isolate_, Handle<Name>(shared->Name(), isolate_))
440 240 : .ToHandleChecked();
441 : Handle<String> source_string =
442 360 : Name::ToFunctionName(isolate_, Handle<Name>(source, isolate_))
443 240 : .ToHandleChecked();
444 :
445 : CodeEvent code_event;
446 : code_event.code_start_address =
447 120 : static_cast<uintptr_t>(code->InstructionStart());
448 120 : code_event.code_size = static_cast<size_t>(code->InstructionSize());
449 120 : code_event.function_name = name_string;
450 120 : code_event.script_name = source_string;
451 120 : code_event.script_line = line;
452 120 : code_event.script_column = column;
453 120 : code_event.code_type = GetCodeEventTypeForTag(tag);
454 120 : code_event.comment = "";
455 :
456 120 : code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
457 120 : }
458 :
459 0 : void ExternalCodeEventListener::CodeCreateEvent(LogEventsAndTags tag,
460 : const wasm::WasmCode* code,
461 : wasm::WasmName name) {
462 : // TODO(mmarchini): handle later
463 0 : }
464 :
465 0 : void ExternalCodeEventListener::RegExpCodeCreateEvent(AbstractCode code,
466 : String source) {
467 : CodeEvent code_event;
468 : code_event.code_start_address =
469 0 : static_cast<uintptr_t>(code->InstructionStart());
470 0 : code_event.code_size = static_cast<size_t>(code->InstructionSize());
471 0 : code_event.function_name = Handle<String>(source, isolate_);
472 0 : code_event.script_name = isolate_->factory()->empty_string();
473 0 : code_event.script_line = 0;
474 0 : code_event.script_column = 0;
475 0 : code_event.code_type = GetCodeEventTypeForTag(CodeEventListener::REG_EXP_TAG);
476 0 : code_event.comment = "";
477 :
478 0 : code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
479 0 : }
480 :
481 : // Low-level logging support.
482 : class LowLevelLogger : public CodeEventLogger {
483 : public:
484 : LowLevelLogger(Isolate* isolate, const char* file_name);
485 : ~LowLevelLogger() override;
486 :
487 : void CodeMoveEvent(AbstractCode from, AbstractCode to) override;
488 0 : void CodeDisableOptEvent(AbstractCode code,
489 0 : SharedFunctionInfo shared) override {}
490 : void SnapshotPositionEvent(HeapObject obj, int pos);
491 : void CodeMovingGCEvent() override;
492 :
493 : private:
494 : void LogRecordedBuffer(AbstractCode code, SharedFunctionInfo shared,
495 : const char* name, int length) override;
496 : void LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
497 : int length) override;
498 :
499 : // Low-level profiling event structures.
500 : struct CodeCreateStruct {
501 : static const char kTag = 'C';
502 :
503 : int32_t name_size;
504 : Address code_address;
505 : int32_t code_size;
506 : };
507 :
508 :
509 : struct CodeMoveStruct {
510 : static const char kTag = 'M';
511 :
512 : Address from_address;
513 : Address to_address;
514 : };
515 :
516 :
517 : static const char kCodeMovingGCTag = 'G';
518 :
519 :
520 : // Extension added to V8 log file name to get the low-level log name.
521 : static const char kLogExt[];
522 :
523 : void LogCodeInfo();
524 : void LogWriteBytes(const char* bytes, int size);
525 :
526 : template <typename T>
527 0 : void LogWriteStruct(const T& s) {
528 0 : char tag = T::kTag;
529 : LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
530 : LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
531 0 : }
532 :
533 : FILE* ll_output_handle_;
534 : };
535 :
536 : const char LowLevelLogger::kLogExt[] = ".ll";
537 :
538 0 : LowLevelLogger::LowLevelLogger(Isolate* isolate, const char* name)
539 0 : : CodeEventLogger(isolate), ll_output_handle_(nullptr) {
540 : // Open the low-level log file.
541 0 : size_t len = strlen(name);
542 0 : ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
543 : MemCopy(ll_name.start(), name, len);
544 0 : MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt));
545 : ll_output_handle_ =
546 0 : base::OS::FOpen(ll_name.start(), base::OS::LogFileOpenMode);
547 0 : setvbuf(ll_output_handle_, nullptr, _IOLBF, 0);
548 :
549 : LogCodeInfo();
550 0 : }
551 :
552 :
553 0 : LowLevelLogger::~LowLevelLogger() {
554 0 : fclose(ll_output_handle_);
555 0 : ll_output_handle_ = nullptr;
556 0 : }
557 :
558 :
559 0 : void LowLevelLogger::LogCodeInfo() {
560 : #if V8_TARGET_ARCH_IA32
561 : const char arch[] = "ia32";
562 : #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_64_BIT
563 0 : const char arch[] = "x64";
564 : #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
565 : const char arch[] = "x32";
566 : #elif V8_TARGET_ARCH_ARM
567 : const char arch[] = "arm";
568 : #elif V8_TARGET_ARCH_PPC
569 : const char arch[] = "ppc";
570 : #elif V8_TARGET_ARCH_MIPS
571 : const char arch[] = "mips";
572 : #elif V8_TARGET_ARCH_ARM64
573 : const char arch[] = "arm64";
574 : #elif V8_TARGET_ARCH_S390
575 : const char arch[] = "s390";
576 : #else
577 : const char arch[] = "unknown";
578 : #endif
579 : LogWriteBytes(arch, sizeof(arch));
580 0 : }
581 :
582 0 : void LowLevelLogger::LogRecordedBuffer(AbstractCode code, SharedFunctionInfo,
583 : const char* name, int length) {
584 : CodeCreateStruct event;
585 0 : event.name_size = length;
586 0 : event.code_address = code->InstructionStart();
587 0 : event.code_size = code->InstructionSize();
588 0 : LogWriteStruct(event);
589 : LogWriteBytes(name, length);
590 0 : LogWriteBytes(reinterpret_cast<const char*>(code->InstructionStart()),
591 0 : code->InstructionSize());
592 0 : }
593 :
594 0 : void LowLevelLogger::LogRecordedBuffer(const wasm::WasmCode* code,
595 : const char* name, int length) {
596 : CodeCreateStruct event;
597 0 : event.name_size = length;
598 0 : event.code_address = code->instruction_start();
599 0 : event.code_size = code->instructions().length();
600 0 : LogWriteStruct(event);
601 : LogWriteBytes(name, length);
602 : LogWriteBytes(reinterpret_cast<const char*>(code->instruction_start()),
603 : code->instructions().length());
604 0 : }
605 :
606 0 : void LowLevelLogger::CodeMoveEvent(AbstractCode from, AbstractCode to) {
607 : CodeMoveStruct event;
608 0 : event.from_address = from->InstructionStart();
609 0 : event.to_address = to->InstructionStart();
610 0 : LogWriteStruct(event);
611 0 : }
612 :
613 0 : void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
614 0 : size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
615 : DCHECK(static_cast<size_t>(size) == rv);
616 : USE(rv);
617 0 : }
618 :
619 :
620 0 : void LowLevelLogger::CodeMovingGCEvent() {
621 0 : const char tag = kCodeMovingGCTag;
622 :
623 : LogWriteBytes(&tag, sizeof(tag));
624 0 : }
625 :
626 105 : class JitLogger : public CodeEventLogger {
627 : public:
628 : JitLogger(Isolate* isolate, JitCodeEventHandler code_event_handler);
629 :
630 : void CodeMoveEvent(AbstractCode from, AbstractCode to) override;
631 10 : void CodeDisableOptEvent(AbstractCode code,
632 10 : SharedFunctionInfo shared) override {}
633 : void AddCodeLinePosInfoEvent(void* jit_handler_data, int pc_offset,
634 : int position,
635 : JitCodeEvent::PositionType position_type);
636 :
637 : void* StartCodePosInfoEvent();
638 : void EndCodePosInfoEvent(Address start_address, void* jit_handler_data);
639 :
640 : private:
641 : void LogRecordedBuffer(AbstractCode code, SharedFunctionInfo shared,
642 : const char* name, int length) override;
643 : void LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
644 : int length) override;
645 :
646 : JitCodeEventHandler code_event_handler_;
647 : base::Mutex logger_mutex_;
648 : };
649 :
650 35 : JitLogger::JitLogger(Isolate* isolate, JitCodeEventHandler code_event_handler)
651 35 : : CodeEventLogger(isolate), code_event_handler_(code_event_handler) {}
652 :
653 5451 : void JitLogger::LogRecordedBuffer(AbstractCode code, SharedFunctionInfo shared,
654 : const char* name, int length) {
655 : JitCodeEvent event;
656 : memset(static_cast<void*>(&event), 0, sizeof(event));
657 : event.type = JitCodeEvent::CODE_ADDED;
658 5451 : event.code_start = reinterpret_cast<void*>(code->InstructionStart());
659 : event.code_type =
660 5451 : code->IsCode() ? JitCodeEvent::JIT_CODE : JitCodeEvent::BYTE_CODE;
661 5451 : event.code_len = code->InstructionSize();
662 : Handle<SharedFunctionInfo> shared_function_handle;
663 5724 : if (!shared.is_null() && shared->script()->IsScript()) {
664 : shared_function_handle =
665 : Handle<SharedFunctionInfo>(shared, shared->GetIsolate());
666 : }
667 5451 : event.script = ToApiHandle<v8::UnboundScript>(shared_function_handle);
668 5451 : event.name.str = name;
669 5451 : event.name.len = length;
670 5451 : event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
671 5451 : code_event_handler_(&event);
672 5451 : }
673 :
674 0 : void JitLogger::LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
675 : int length) {
676 : JitCodeEvent event;
677 : memset(static_cast<void*>(&event), 0, sizeof(event));
678 : event.type = JitCodeEvent::CODE_ADDED;
679 0 : event.code_type = JitCodeEvent::JIT_CODE;
680 0 : event.code_start = code->instructions().start();
681 0 : event.code_len = code->instructions().length();
682 0 : event.name.str = name;
683 0 : event.name.len = length;
684 0 : event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
685 0 : code_event_handler_(&event);
686 0 : }
687 :
688 171 : void JitLogger::CodeMoveEvent(AbstractCode from, AbstractCode to) {
689 171 : base::MutexGuard guard(&logger_mutex_);
690 :
691 : JitCodeEvent event;
692 171 : event.type = JitCodeEvent::CODE_MOVED;
693 : event.code_type =
694 171 : from->IsCode() ? JitCodeEvent::JIT_CODE : JitCodeEvent::BYTE_CODE;
695 171 : event.code_start = reinterpret_cast<void*>(from->InstructionStart());
696 171 : event.code_len = from->InstructionSize();
697 171 : event.new_code_start = reinterpret_cast<void*>(to->InstructionStart());
698 171 : event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
699 :
700 171 : code_event_handler_(&event);
701 171 : }
702 :
703 2139 : void JitLogger::AddCodeLinePosInfoEvent(
704 : void* jit_handler_data,
705 : int pc_offset,
706 : int position,
707 : JitCodeEvent::PositionType position_type) {
708 : JitCodeEvent event;
709 : memset(static_cast<void*>(&event), 0, sizeof(event));
710 2139 : event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
711 2139 : event.user_data = jit_handler_data;
712 2139 : event.line_info.offset = pc_offset;
713 2139 : event.line_info.pos = position;
714 2139 : event.line_info.position_type = position_type;
715 2139 : event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
716 :
717 2139 : code_event_handler_(&event);
718 2139 : }
719 :
720 :
721 230 : void* JitLogger::StartCodePosInfoEvent() {
722 : JitCodeEvent event;
723 : memset(static_cast<void*>(&event), 0, sizeof(event));
724 230 : event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
725 230 : event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
726 :
727 230 : code_event_handler_(&event);
728 230 : return event.user_data;
729 : }
730 :
731 230 : void JitLogger::EndCodePosInfoEvent(Address start_address,
732 : void* jit_handler_data) {
733 : JitCodeEvent event;
734 : memset(static_cast<void*>(&event), 0, sizeof(event));
735 230 : event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
736 230 : event.code_start = reinterpret_cast<void*>(start_address);
737 230 : event.user_data = jit_handler_data;
738 230 : event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
739 :
740 230 : code_event_handler_(&event);
741 230 : }
742 :
743 :
744 : // TODO(lpy): Keeping sampling thread inside V8 is a workaround currently,
745 : // the reason is to reduce code duplication during migration to sampler library,
746 : // sampling thread, as well as the sampler, will be moved to D8 eventually.
747 62868 : class SamplingThread : public base::Thread {
748 : public:
749 : static const int kSamplingThreadStackSize = 64 * KB;
750 :
751 : SamplingThread(sampler::Sampler* sampler, int interval_microseconds)
752 : : base::Thread(
753 : base::Thread::Options("SamplingThread", kSamplingThreadStackSize)),
754 : sampler_(sampler),
755 62883 : interval_microseconds_(interval_microseconds) {}
756 0 : void Run() override {
757 0 : while (sampler_->IsProfiling()) {
758 0 : sampler_->DoSample();
759 : base::OS::Sleep(
760 0 : base::TimeDelta::FromMicroseconds(interval_microseconds_));
761 : }
762 0 : }
763 :
764 : private:
765 : sampler::Sampler* sampler_;
766 : const int interval_microseconds_;
767 : };
768 :
769 :
770 : // The Profiler samples pc and sp values for the main thread.
771 : // Each sample is appended to a circular buffer.
772 : // An independent thread removes data and writes it to the log.
773 : // This design minimizes the time spent in the sampler.
774 : //
775 0 : class Profiler: public base::Thread {
776 : public:
777 : explicit Profiler(Isolate* isolate);
778 : void Engage();
779 : void Disengage();
780 :
781 : // Inserts collected profiling data into buffer.
782 0 : void Insert(v8::TickSample* sample) {
783 0 : if (paused_)
784 0 : return;
785 :
786 0 : if (Succ(head_) == static_cast<int>(base::Relaxed_Load(&tail_))) {
787 0 : overflow_ = true;
788 : } else {
789 0 : buffer_[head_] = *sample;
790 0 : head_ = Succ(head_);
791 0 : buffer_semaphore_.Signal(); // Tell we have an element.
792 : }
793 : }
794 :
795 : void Run() override;
796 :
797 : // Pause and Resume TickSample data collection.
798 0 : void Pause() { paused_ = true; }
799 0 : void Resume() { paused_ = false; }
800 :
801 : private:
802 : // Waits for a signal and removes profiling data.
803 0 : bool Remove(v8::TickSample* sample) {
804 0 : buffer_semaphore_.Wait(); // Wait for an element.
805 0 : *sample = buffer_[base::Relaxed_Load(&tail_)];
806 0 : bool result = overflow_;
807 : base::Relaxed_Store(
808 : &tail_, static_cast<base::Atomic32>(Succ(base::Relaxed_Load(&tail_))));
809 0 : overflow_ = false;
810 0 : return result;
811 : }
812 :
813 : // Returns the next index in the cyclic buffer.
814 0 : int Succ(int index) { return (index + 1) % kBufferSize; }
815 :
816 : Isolate* isolate_;
817 : // Cyclic buffer for communicating profiling samples
818 : // between the signal handler and the worker thread.
819 : static const int kBufferSize = 128;
820 : v8::TickSample buffer_[kBufferSize]; // Buffer storage.
821 : int head_; // Index to the buffer head.
822 : base::Atomic32 tail_; // Index to the buffer tail.
823 : bool overflow_; // Tell whether a buffer overflow has occurred.
824 : // Semaphore used for buffer synchronization.
825 : base::Semaphore buffer_semaphore_;
826 :
827 : // Tells whether profiler is engaged, that is, processing thread is stated.
828 : bool engaged_;
829 :
830 : // Tells whether worker thread should continue running.
831 : base::Atomic32 running_;
832 :
833 : // Tells whether we are currently recording tick samples.
834 : bool paused_;
835 : };
836 :
837 :
838 : //
839 : // Ticker used to provide ticks to the profiler and the sliding state
840 : // window.
841 : //
842 : class Ticker: public sampler::Sampler {
843 : public:
844 62883 : Ticker(Isolate* isolate, int interval_microseconds)
845 : : sampler::Sampler(reinterpret_cast<v8::Isolate*>(isolate)),
846 : profiler_(nullptr),
847 125766 : sampling_thread_(new SamplingThread(this, interval_microseconds)) {}
848 :
849 188604 : ~Ticker() override {
850 62868 : if (IsActive()) Stop();
851 62868 : delete sampling_thread_;
852 125736 : }
853 :
854 0 : void SetProfiler(Profiler* profiler) {
855 : DCHECK_NULL(profiler_);
856 0 : profiler_ = profiler;
857 0 : IncreaseProfilingDepth();
858 0 : if (!IsActive()) Start();
859 0 : sampling_thread_->StartSynchronously();
860 0 : }
861 :
862 0 : void ClearProfiler() {
863 0 : profiler_ = nullptr;
864 0 : if (IsActive()) Stop();
865 0 : DecreaseProfilingDepth();
866 0 : sampling_thread_->Join();
867 0 : }
868 :
869 0 : void SampleStack(const v8::RegisterState& state) override {
870 0 : if (!profiler_) return;
871 0 : Isolate* isolate = reinterpret_cast<Isolate*>(this->isolate());
872 : TickSample sample;
873 0 : sample.Init(isolate, state, TickSample::kIncludeCEntryFrame, true);
874 0 : profiler_->Insert(&sample);
875 : }
876 :
877 : private:
878 : Profiler* profiler_;
879 : SamplingThread* sampling_thread_;
880 : };
881 :
882 : //
883 : // Profiler implementation when invoking with --prof.
884 : //
885 0 : Profiler::Profiler(Isolate* isolate)
886 : : base::Thread(Options("v8:Profiler")),
887 : isolate_(isolate),
888 : head_(0),
889 : overflow_(false),
890 : buffer_semaphore_(0),
891 : engaged_(false),
892 0 : paused_(false) {
893 0 : base::Relaxed_Store(&tail_, 0);
894 0 : base::Relaxed_Store(&running_, 0);
895 0 : }
896 :
897 :
898 0 : void Profiler::Engage() {
899 0 : if (engaged_) return;
900 0 : engaged_ = true;
901 :
902 : std::vector<base::OS::SharedLibraryAddress> addresses =
903 0 : base::OS::GetSharedLibraryAddresses();
904 0 : for (const auto& address : addresses) {
905 0 : LOG(isolate_, SharedLibraryEvent(address.library_path, address.start,
906 : address.end, address.aslr_slide));
907 : }
908 :
909 : // Start thread processing the profiler buffer.
910 0 : base::Relaxed_Store(&running_, 1);
911 0 : Start();
912 :
913 : // Register to get ticks.
914 0 : Logger* logger = isolate_->logger();
915 0 : logger->ticker_->SetProfiler(this);
916 :
917 0 : logger->ProfilerBeginEvent();
918 : }
919 :
920 :
921 0 : void Profiler::Disengage() {
922 0 : if (!engaged_) return;
923 :
924 : // Stop receiving ticks.
925 0 : isolate_->logger()->ticker_->ClearProfiler();
926 :
927 : // Terminate the worker thread by setting running_ to false,
928 : // inserting a fake element in the queue and then wait for
929 : // the thread to terminate.
930 0 : base::Relaxed_Store(&running_, 0);
931 : v8::TickSample sample;
932 : // Reset 'paused_' flag, otherwise semaphore may not be signalled.
933 : Resume();
934 0 : Insert(&sample);
935 0 : Join();
936 :
937 0 : LOG(isolate_, UncheckedStringEvent("profiler", "end"));
938 : }
939 :
940 :
941 0 : void Profiler::Run() {
942 : v8::TickSample sample;
943 0 : bool overflow = Remove(&sample);
944 0 : while (base::Relaxed_Load(&running_)) {
945 0 : LOG(isolate_, TickEvent(&sample, overflow));
946 0 : overflow = Remove(&sample);
947 : }
948 0 : }
949 :
950 :
951 : //
952 : // Logger class implementation.
953 : //
954 :
955 62882 : Logger::Logger(Isolate* isolate)
956 : : isolate_(isolate),
957 : ticker_(nullptr),
958 : profiler_(nullptr),
959 : log_events_(nullptr),
960 : is_logging_(false),
961 : log_(nullptr),
962 : perf_basic_logger_(nullptr),
963 : perf_jit_logger_(nullptr),
964 : ll_logger_(nullptr),
965 : jit_logger_(nullptr),
966 : is_initialized_(false),
967 188646 : existing_code_logger_(isolate) {}
968 :
969 125734 : Logger::~Logger() {
970 125735 : delete log_;
971 125734 : }
972 :
973 1341 : void Logger::AddCodeEventListener(CodeEventListener* listener) {
974 2682 : bool result = isolate_->code_event_dispatcher()->AddListener(listener);
975 1341 : CHECK(result);
976 1341 : }
977 :
978 1240 : void Logger::RemoveCodeEventListener(CodeEventListener* listener) {
979 2550 : isolate_->code_event_dispatcher()->RemoveListener(listener);
980 1240 : }
981 :
982 0 : void Logger::ProfilerBeginEvent() {
983 0 : if (!log_->IsEnabled()) return;
984 0 : Log::MessageBuilder msg(log_);
985 0 : msg << "profiler" << kNext << "begin" << kNext << FLAG_prof_sampling_interval;
986 0 : msg.WriteToLogFile();
987 : }
988 :
989 :
990 0 : void Logger::StringEvent(const char* name, const char* value) {
991 0 : if (FLAG_log) UncheckedStringEvent(name, value);
992 0 : }
993 :
994 :
995 0 : void Logger::UncheckedStringEvent(const char* name, const char* value) {
996 0 : if (!log_->IsEnabled()) return;
997 0 : Log::MessageBuilder msg(log_);
998 0 : msg << name << kNext << value;
999 0 : msg.WriteToLogFile();
1000 : }
1001 :
1002 :
1003 122 : void Logger::IntPtrTEvent(const char* name, intptr_t value) {
1004 122 : if (FLAG_log) UncheckedIntPtrTEvent(name, value);
1005 122 : }
1006 :
1007 :
1008 122 : void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
1009 244 : if (!log_->IsEnabled()) return;
1010 122 : Log::MessageBuilder msg(log_);
1011 122 : msg << name << kNext;
1012 122 : msg.AppendFormatString("%" V8PRIdPTR, value);
1013 122 : msg.WriteToLogFile();
1014 : }
1015 :
1016 0 : void Logger::HandleEvent(const char* name, Address* location) {
1017 0 : if (!log_->IsEnabled() || !FLAG_log_handles) return;
1018 0 : Log::MessageBuilder msg(log_);
1019 0 : msg << name << kNext << reinterpret_cast<void*>(location);
1020 0 : msg.WriteToLogFile();
1021 : }
1022 :
1023 :
1024 0 : void Logger::ApiSecurityCheck() {
1025 0 : if (!log_->IsEnabled() || !FLAG_log_api) return;
1026 0 : Log::MessageBuilder msg(log_);
1027 0 : msg << "api" << kNext << "check-security";
1028 0 : msg.WriteToLogFile();
1029 : }
1030 :
1031 0 : void Logger::SharedLibraryEvent(const std::string& library_path,
1032 : uintptr_t start, uintptr_t end,
1033 : intptr_t aslr_slide) {
1034 0 : if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
1035 0 : Log::MessageBuilder msg(log_);
1036 0 : msg << "shared-library" << kNext << library_path.c_str() << kNext
1037 0 : << reinterpret_cast<void*>(start) << kNext << reinterpret_cast<void*>(end)
1038 0 : << kNext << aslr_slide;
1039 0 : msg.WriteToLogFile();
1040 : }
1041 :
1042 6 : void Logger::CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc,
1043 : int fp_to_sp_delta) {
1044 12 : if (!log_->IsEnabled()) return;
1045 6 : Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
1046 6 : Log::MessageBuilder msg(log_);
1047 18 : msg << "code-deopt" << kNext << timer_.Elapsed().InMicroseconds() << kNext
1048 6 : << code->CodeSize() << kNext
1049 12 : << reinterpret_cast<void*>(code->InstructionStart());
1050 :
1051 : // Deoptimization position.
1052 12 : std::ostringstream deopt_location;
1053 : int inlining_id = -1;
1054 : int script_offset = -1;
1055 6 : if (info.position.IsKnown()) {
1056 6 : info.position.Print(deopt_location, code);
1057 : inlining_id = info.position.InliningId();
1058 : script_offset = info.position.ScriptOffset();
1059 : } else {
1060 0 : deopt_location << "<unknown>";
1061 : }
1062 18 : msg << kNext << inlining_id << kNext << script_offset << kNext;
1063 6 : msg << Deoptimizer::MessageFor(kind) << kNext;
1064 12 : msg << deopt_location.str().c_str() << kNext
1065 12 : << DeoptimizeReasonToString(info.deopt_reason);
1066 6 : msg.WriteToLogFile();
1067 : }
1068 :
1069 :
1070 0 : void Logger::CurrentTimeEvent() {
1071 0 : if (!log_->IsEnabled()) return;
1072 : DCHECK(FLAG_log_internal_timer_events);
1073 0 : Log::MessageBuilder msg(log_);
1074 0 : msg << "current-time" << kNext << timer_.Elapsed().InMicroseconds();
1075 0 : msg.WriteToLogFile();
1076 : }
1077 :
1078 :
1079 509 : void Logger::TimerEvent(Logger::StartEnd se, const char* name) {
1080 1018 : if (!log_->IsEnabled()) return;
1081 509 : Log::MessageBuilder msg(log_);
1082 509 : switch (se) {
1083 : case START:
1084 247 : msg << "timer-event-start";
1085 247 : break;
1086 : case END:
1087 247 : msg << "timer-event-end";
1088 247 : break;
1089 : case STAMP:
1090 15 : msg << "timer-event";
1091 : }
1092 1018 : msg << kNext << name << kNext << timer_.Elapsed().InMicroseconds();
1093 509 : msg.WriteToLogFile();
1094 : }
1095 :
1096 : // static
1097 0 : void Logger::EnterExternal(Isolate* isolate) {
1098 : DCHECK(FLAG_log_internal_timer_events);
1099 0 : LOG(isolate, TimerEvent(START, TimerEventExternal::name()));
1100 : DCHECK(isolate->current_vm_state() == JS);
1101 : isolate->set_current_vm_state(EXTERNAL);
1102 0 : }
1103 :
1104 : // static
1105 0 : void Logger::LeaveExternal(Isolate* isolate) {
1106 : DCHECK(FLAG_log_internal_timer_events);
1107 0 : LOG(isolate, TimerEvent(END, TimerEventExternal::name()));
1108 : DCHECK(isolate->current_vm_state() == EXTERNAL);
1109 : isolate->set_current_vm_state(JS);
1110 0 : }
1111 :
1112 : // Instantiate template methods.
1113 : #define V(TimerName, expose) \
1114 : template void TimerEventScope<TimerEvent##TimerName>::LogTimerEvent( \
1115 : Logger::StartEnd se);
1116 : TIMER_EVENTS_LIST(V)
1117 : #undef V
1118 :
1119 0 : void Logger::ApiNamedPropertyAccess(const char* tag, JSObject holder,
1120 : Object property_name) {
1121 : DCHECK(property_name->IsName());
1122 0 : if (!log_->IsEnabled() || !FLAG_log_api) return;
1123 0 : Log::MessageBuilder msg(log_);
1124 0 : msg << "api" << kNext << tag << kNext << holder->class_name() << kNext
1125 0 : << Name::cast(property_name);
1126 0 : msg.WriteToLogFile();
1127 : }
1128 :
1129 0 : void Logger::ApiIndexedPropertyAccess(const char* tag, JSObject holder,
1130 : uint32_t index) {
1131 0 : if (!log_->IsEnabled() || !FLAG_log_api) return;
1132 0 : Log::MessageBuilder msg(log_);
1133 0 : msg << "api" << kNext << tag << kNext << holder->class_name() << kNext
1134 : << index;
1135 0 : msg.WriteToLogFile();
1136 : }
1137 :
1138 0 : void Logger::ApiObjectAccess(const char* tag, JSObject object) {
1139 0 : if (!log_->IsEnabled() || !FLAG_log_api) return;
1140 0 : Log::MessageBuilder msg(log_);
1141 0 : msg << "api" << kNext << tag << kNext << object->class_name();
1142 0 : msg.WriteToLogFile();
1143 : }
1144 :
1145 2090 : void Logger::ApiEntryCall(const char* name) {
1146 6120 : if (!log_->IsEnabled() || !FLAG_log_api) return;
1147 150 : Log::MessageBuilder msg(log_);
1148 150 : msg << "api" << kNext << name;
1149 150 : msg.WriteToLogFile();
1150 : }
1151 :
1152 :
1153 636 : void Logger::NewEvent(const char* name, void* object, size_t size) {
1154 1272 : if (!log_->IsEnabled() || !FLAG_log) return;
1155 636 : Log::MessageBuilder msg(log_);
1156 636 : msg << "new" << kNext << name << kNext << object << kNext
1157 : << static_cast<unsigned int>(size);
1158 636 : msg.WriteToLogFile();
1159 : }
1160 :
1161 :
1162 608 : void Logger::DeleteEvent(const char* name, void* object) {
1163 1824 : if (!log_->IsEnabled() || !FLAG_log) return;
1164 0 : Log::MessageBuilder msg(log_);
1165 0 : msg << "delete" << kNext << name << kNext << object;
1166 0 : msg.WriteToLogFile();
1167 : }
1168 :
1169 445 : void Logger::CallbackEventInternal(const char* prefix, Name name,
1170 : Address entry_point) {
1171 890 : if (!FLAG_log_code || !log_->IsEnabled()) return;
1172 445 : Log::MessageBuilder msg(log_);
1173 445 : msg << kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT] << kNext
1174 890 : << kLogEventsNames[CodeEventListener::CALLBACK_TAG] << kNext << -2
1175 1780 : << kNext << timer_.Elapsed().InMicroseconds() << kNext
1176 1335 : << reinterpret_cast<void*>(entry_point) << kNext << 1 << kNext << prefix
1177 445 : << name;
1178 445 : msg.WriteToLogFile();
1179 : }
1180 :
1181 320 : void Logger::CallbackEvent(Name name, Address entry_point) {
1182 320 : CallbackEventInternal("", name, entry_point);
1183 320 : }
1184 :
1185 65 : void Logger::GetterCallbackEvent(Name name, Address entry_point) {
1186 65 : CallbackEventInternal("get ", name, entry_point);
1187 65 : }
1188 :
1189 60 : void Logger::SetterCallbackEvent(Name name, Address entry_point) {
1190 60 : CallbackEventInternal("set ", name, entry_point);
1191 60 : }
1192 :
1193 : namespace {
1194 :
1195 5375 : void AppendCodeCreateHeader(Log::MessageBuilder& msg,
1196 : CodeEventListener::LogEventsAndTags tag,
1197 : AbstractCode::Kind kind, uint8_t* address, int size,
1198 : base::ElapsedTimer* timer) {
1199 5375 : msg << kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT]
1200 10750 : << Logger::kNext << kLogEventsNames[tag] << Logger::kNext << kind
1201 21500 : << Logger::kNext << timer->Elapsed().InMicroseconds() << Logger::kNext
1202 5375 : << reinterpret_cast<void*>(address) << Logger::kNext << size
1203 5375 : << Logger::kNext;
1204 5375 : }
1205 :
1206 5375 : void AppendCodeCreateHeader(Log::MessageBuilder& msg,
1207 : CodeEventListener::LogEventsAndTags tag,
1208 : AbstractCode code, base::ElapsedTimer* timer) {
1209 : AppendCodeCreateHeader(msg, tag, code->kind(),
1210 5375 : reinterpret_cast<uint8_t*>(code->InstructionStart()),
1211 10750 : code->InstructionSize(), timer);
1212 5375 : }
1213 :
1214 : } // namespace
1215 :
1216 5175 : void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
1217 : AbstractCode code, const char* comment) {
1218 5175 : if (!is_listening_to_code_events()) return;
1219 10350 : if (!FLAG_log_code || !log_->IsEnabled()) return;
1220 5175 : Log::MessageBuilder msg(log_);
1221 5175 : AppendCodeCreateHeader(msg, tag, code, &timer_);
1222 5175 : msg << comment;
1223 5175 : msg.WriteToLogFile();
1224 : }
1225 :
1226 0 : void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
1227 : AbstractCode code, Name name) {
1228 0 : if (!is_listening_to_code_events()) return;
1229 0 : if (!FLAG_log_code || !log_->IsEnabled()) return;
1230 0 : Log::MessageBuilder msg(log_);
1231 0 : AppendCodeCreateHeader(msg, tag, code, &timer_);
1232 0 : msg << name;
1233 0 : msg.WriteToLogFile();
1234 : }
1235 :
1236 0 : void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
1237 : AbstractCode code, SharedFunctionInfo shared,
1238 : Name name) {
1239 0 : if (!is_listening_to_code_events()) return;
1240 0 : if (!FLAG_log_code || !log_->IsEnabled()) return;
1241 0 : if (code == AbstractCode::cast(
1242 0 : isolate_->builtins()->builtin(Builtins::kCompileLazy))) {
1243 : return;
1244 : }
1245 :
1246 0 : Log::MessageBuilder msg(log_);
1247 0 : AppendCodeCreateHeader(msg, tag, code, &timer_);
1248 0 : msg << name << kNext << reinterpret_cast<void*>(shared->address()) << kNext
1249 0 : << ComputeMarker(shared, code);
1250 0 : msg.WriteToLogFile();
1251 : }
1252 :
1253 0 : void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
1254 0 : const wasm::WasmCode* code, wasm::WasmName name) {
1255 0 : if (!is_listening_to_code_events()) return;
1256 0 : if (!FLAG_log_code || !log_->IsEnabled()) return;
1257 0 : Log::MessageBuilder msg(log_);
1258 : AppendCodeCreateHeader(msg, tag, AbstractCode::Kind::WASM_FUNCTION,
1259 : code->instructions().start(),
1260 0 : code->instructions().length(), &timer_);
1261 0 : if (name.is_empty()) {
1262 0 : msg << "<unknown wasm>";
1263 : } else {
1264 0 : msg.AppendString(name);
1265 : }
1266 : // We have to add two extra fields that allow the tick processor to group
1267 : // events for the same wasm function, even if it gets compiled again. For
1268 : // normal JS functions, we use the shared function info. For wasm, the pointer
1269 : // to the native module + function index works well enough.
1270 : // TODO(herhut) Clean up the tick processor code instead.
1271 : void* tag_ptr =
1272 0 : reinterpret_cast<byte*>(code->native_module()) + code->index();
1273 0 : msg << kNext << tag_ptr << kNext << ComputeMarker(code);
1274 0 : msg.WriteToLogFile();
1275 : }
1276 :
1277 : // Although, it is possible to extract source and line from
1278 : // the SharedFunctionInfo object, we left it to caller
1279 : // to leave logging functions free from heap allocations.
1280 200 : void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
1281 : AbstractCode code, SharedFunctionInfo shared,
1282 : Name source, int line, int column) {
1283 400 : if (!is_listening_to_code_events()) return;
1284 400 : if (!FLAG_log_code || !log_->IsEnabled()) return;
1285 : {
1286 200 : Log::MessageBuilder msg(log_);
1287 200 : AppendCodeCreateHeader(msg, tag, code, &timer_);
1288 400 : msg << shared->DebugName() << " " << source << ":" << line << ":" << column
1289 400 : << kNext << reinterpret_cast<void*>(shared->address()) << kNext
1290 400 : << ComputeMarker(shared, code);
1291 200 : msg.WriteToLogFile();
1292 : }
1293 :
1294 200 : if (!FLAG_log_source_code) return;
1295 0 : Object script_object = shared->script();
1296 0 : if (!script_object->IsScript()) return;
1297 : Script script = Script::cast(script_object);
1298 0 : if (!EnsureLogScriptSource(script)) return;
1299 :
1300 : // We log source code information in the form:
1301 : //
1302 : // code-source-info <addr>,<script>,<start>,<end>,<pos>,<inline-pos>,<fns>
1303 : //
1304 : // where
1305 : // <addr> is code object address
1306 : // <script> is script id
1307 : // <start> is the starting position inside the script
1308 : // <end> is the end position inside the script
1309 : // <pos> is source position table encoded in the string,
1310 : // it is a sequence of C<code-offset>O<script-offset>[I<inlining-id>]
1311 : // where
1312 : // <code-offset> is the offset within the code object
1313 : // <script-offset> is the position within the script
1314 : // <inlining-id> is the offset in the <inlining> table
1315 : // <inlining> table is a sequence of strings of the form
1316 : // F<function-id>O<script-offset>[I<inlining-id>]
1317 : // where
1318 : // <function-id> is an index into the <fns> function table
1319 : // <fns> is the function table encoded as a sequence of strings
1320 : // S<shared-function-info-address>
1321 0 : Log::MessageBuilder msg(log_);
1322 0 : msg << "code-source-info" << kNext
1323 0 : << reinterpret_cast<void*>(code->InstructionStart()) << kNext
1324 0 : << script->id() << kNext << shared->StartPosition() << kNext
1325 0 : << shared->EndPosition() << kNext;
1326 :
1327 0 : SourcePositionTableIterator iterator(code->source_position_table());
1328 : bool hasInlined = false;
1329 0 : for (; !iterator.done(); iterator.Advance()) {
1330 0 : SourcePosition pos = iterator.source_position();
1331 0 : msg << "C" << iterator.code_offset() << "O" << pos.ScriptOffset();
1332 0 : if (pos.isInlined()) {
1333 0 : msg << "I" << pos.InliningId();
1334 : hasInlined = true;
1335 : }
1336 : }
1337 0 : msg << kNext;
1338 : int maxInlinedId = -1;
1339 0 : if (hasInlined) {
1340 : PodArray<InliningPosition> inlining_positions =
1341 0 : DeoptimizationData::cast(Code::cast(code)->deoptimization_data())
1342 0 : ->InliningPositions();
1343 0 : for (int i = 0; i < inlining_positions->length(); i++) {
1344 : InliningPosition inlining_pos = inlining_positions->get(i);
1345 0 : msg << "F";
1346 0 : if (inlining_pos.inlined_function_id != -1) {
1347 : msg << inlining_pos.inlined_function_id;
1348 0 : if (inlining_pos.inlined_function_id > maxInlinedId) {
1349 : maxInlinedId = inlining_pos.inlined_function_id;
1350 : }
1351 : }
1352 : SourcePosition pos = inlining_pos.position;
1353 0 : msg << "O" << pos.ScriptOffset();
1354 0 : if (pos.isInlined()) {
1355 0 : msg << "I" << pos.InliningId();
1356 : }
1357 : }
1358 : }
1359 0 : msg << kNext;
1360 0 : if (hasInlined) {
1361 : DeoptimizationData deopt_data =
1362 0 : DeoptimizationData::cast(Code::cast(code)->deoptimization_data());
1363 :
1364 : msg << std::hex;
1365 0 : for (int i = 0; i <= maxInlinedId; i++) {
1366 0 : msg << "S"
1367 : << reinterpret_cast<void*>(
1368 0 : deopt_data->GetInlinedFunction(i)->address());
1369 : }
1370 : msg << std::dec;
1371 : }
1372 0 : msg.WriteToLogFile();
1373 : }
1374 :
1375 1 : void Logger::CodeDisableOptEvent(AbstractCode code, SharedFunctionInfo shared) {
1376 1 : if (!is_listening_to_code_events()) return;
1377 2 : if (!FLAG_log_code || !log_->IsEnabled()) return;
1378 1 : Log::MessageBuilder msg(log_);
1379 1 : msg << kLogEventsNames[CodeEventListener::CODE_DISABLE_OPT_EVENT] << kNext
1380 2 : << shared->DebugName() << kNext
1381 2 : << GetBailoutReason(shared->disable_optimization_reason());
1382 1 : msg.WriteToLogFile();
1383 : }
1384 :
1385 24 : void Logger::CodeMovingGCEvent() {
1386 24 : if (!is_listening_to_code_events()) return;
1387 48 : if (!log_->IsEnabled() || !FLAG_ll_prof) return;
1388 0 : base::OS::SignalCodeMovingGC();
1389 : }
1390 :
1391 0 : void Logger::RegExpCodeCreateEvent(AbstractCode code, String source) {
1392 0 : if (!is_listening_to_code_events()) return;
1393 0 : if (!FLAG_log_code || !log_->IsEnabled()) return;
1394 0 : Log::MessageBuilder msg(log_);
1395 0 : AppendCodeCreateHeader(msg, CodeEventListener::REG_EXP_TAG, code, &timer_);
1396 0 : msg << source;
1397 0 : msg.WriteToLogFile();
1398 : }
1399 :
1400 0 : void Logger::CodeMoveEvent(AbstractCode from, AbstractCode to) {
1401 0 : if (!is_listening_to_code_events()) return;
1402 : MoveEventInternal(CodeEventListener::CODE_MOVE_EVENT, from->address(),
1403 0 : to->address());
1404 : }
1405 :
1406 : namespace {
1407 :
1408 387 : void CodeLinePosEvent(JitLogger* jit_logger, Address code_start,
1409 7436 : SourcePositionTableIterator& iter) {
1410 387 : if (jit_logger) {
1411 230 : void* jit_handler_data = jit_logger->StartCodePosInfoEvent();
1412 3388 : for (; !iter.done(); iter.Advance()) {
1413 1464 : if (iter.is_statement()) {
1414 : jit_logger->AddCodeLinePosInfoEvent(
1415 : jit_handler_data, iter.code_offset(),
1416 : iter.source_position().ScriptOffset(),
1417 675 : JitCodeEvent::STATEMENT_POSITION);
1418 : }
1419 : jit_logger->AddCodeLinePosInfoEvent(jit_handler_data, iter.code_offset(),
1420 : iter.source_position().ScriptOffset(),
1421 1464 : JitCodeEvent::POSITION);
1422 : }
1423 230 : jit_logger->EndCodePosInfoEvent(code_start, jit_handler_data);
1424 : }
1425 387 : }
1426 :
1427 : } // namespace
1428 :
1429 387 : void Logger::CodeLinePosInfoRecordEvent(Address code_start,
1430 : ByteArray source_position_table) {
1431 387 : SourcePositionTableIterator iter(source_position_table);
1432 387 : CodeLinePosEvent(jit_logger_, code_start, iter);
1433 387 : }
1434 :
1435 0 : void Logger::CodeLinePosInfoRecordEvent(
1436 : Address code_start, Vector<const byte> source_position_table) {
1437 0 : SourcePositionTableIterator iter(source_position_table);
1438 0 : CodeLinePosEvent(jit_logger_, code_start, iter);
1439 0 : }
1440 :
1441 0 : void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
1442 0 : if (code_name == nullptr) return; // Not a code object.
1443 0 : Log::MessageBuilder msg(log_);
1444 0 : msg << kLogEventsNames[CodeEventListener::SNAPSHOT_CODE_NAME_EVENT] << kNext
1445 0 : << pos << kNext << code_name;
1446 0 : msg.WriteToLogFile();
1447 : }
1448 :
1449 :
1450 2069 : void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
1451 4138 : if (!is_listening_to_code_events()) return;
1452 2069 : MoveEventInternal(CodeEventListener::SHARED_FUNC_MOVE_EVENT, from, to);
1453 : }
1454 :
1455 2069 : void Logger::MoveEventInternal(CodeEventListener::LogEventsAndTags event,
1456 : Address from, Address to) {
1457 4138 : if (!FLAG_log_code || !log_->IsEnabled()) return;
1458 0 : Log::MessageBuilder msg(log_);
1459 0 : msg << kLogEventsNames[event] << kNext << reinterpret_cast<void*>(from)
1460 0 : << kNext << reinterpret_cast<void*>(to);
1461 0 : msg.WriteToLogFile();
1462 : }
1463 :
1464 :
1465 64 : void Logger::ResourceEvent(const char* name, const char* tag) {
1466 128 : if (!log_->IsEnabled() || !FLAG_log) return;
1467 64 : Log::MessageBuilder msg(log_);
1468 64 : msg << name << kNext << tag << kNext;
1469 :
1470 : uint32_t sec, usec;
1471 64 : if (base::OS::GetUserTime(&sec, &usec) != -1) {
1472 192 : msg << sec << kNext << usec << kNext;
1473 : }
1474 : msg.AppendFormatString("%.0f",
1475 64 : V8::GetCurrentPlatform()->CurrentClockTimeMillis());
1476 64 : msg.WriteToLogFile();
1477 : }
1478 :
1479 0 : void Logger::SuspectReadEvent(Name name, Object obj) {
1480 0 : if (!log_->IsEnabled() || !FLAG_log_suspect) return;
1481 0 : Log::MessageBuilder msg(log_);
1482 : String class_name = obj->IsJSObject()
1483 0 : ? JSObject::cast(obj)->class_name()
1484 0 : : ReadOnlyRoots(isolate_).empty_string();
1485 0 : msg << "suspect-read" << kNext << class_name << kNext << name;
1486 0 : msg.WriteToLogFile();
1487 : }
1488 :
1489 : namespace {
1490 244 : void AppendFunctionMessage(Log::MessageBuilder& msg, const char* reason,
1491 : int script_id, double time_delta, int start_position,
1492 : int end_position, base::ElapsedTimer* timer) {
1493 244 : msg << "function" << Logger::kNext << reason << Logger::kNext << script_id
1494 488 : << Logger::kNext << start_position << Logger::kNext << end_position
1495 488 : << Logger::kNext << time_delta << Logger::kNext
1496 488 : << timer->Elapsed().InMicroseconds() << Logger::kNext;
1497 244 : }
1498 : } // namespace
1499 :
1500 112 : void Logger::FunctionEvent(const char* reason, int script_id, double time_delta,
1501 : int start_position, int end_position,
1502 : String function_name) {
1503 224 : if (!log_->IsEnabled() || !FLAG_log_function_events) return;
1504 112 : Log::MessageBuilder msg(log_);
1505 : AppendFunctionMessage(msg, reason, script_id, time_delta, start_position,
1506 112 : end_position, &timer_);
1507 112 : if (!function_name.is_null()) msg << function_name;
1508 112 : msg.WriteToLogFile();
1509 : }
1510 :
1511 132 : void Logger::FunctionEvent(const char* reason, int script_id, double time_delta,
1512 : int start_position, int end_position,
1513 : const char* function_name,
1514 : size_t function_name_length) {
1515 264 : if (!log_->IsEnabled() || !FLAG_log_function_events) return;
1516 132 : Log::MessageBuilder msg(log_);
1517 : AppendFunctionMessage(msg, reason, script_id, time_delta, start_position,
1518 132 : end_position, &timer_);
1519 132 : if (function_name_length > 0) {
1520 91 : msg.AppendString(function_name, function_name_length);
1521 : }
1522 132 : msg.WriteToLogFile();
1523 : }
1524 :
1525 54 : void Logger::CompilationCacheEvent(const char* action, const char* cache_type,
1526 : SharedFunctionInfo sfi) {
1527 149 : if (!log_->IsEnabled() || !FLAG_log_function_events) return;
1528 13 : Log::MessageBuilder msg(log_);
1529 : int script_id = -1;
1530 26 : if (sfi->script()->IsScript()) {
1531 13 : script_id = Script::cast(sfi->script())->id();
1532 : }
1533 13 : msg << "compilation-cache" << Logger::kNext << action << Logger::kNext
1534 26 : << cache_type << Logger::kNext << script_id << Logger::kNext
1535 26 : << sfi->StartPosition() << Logger::kNext << sfi->EndPosition()
1536 39 : << Logger::kNext << timer_.Elapsed().InMicroseconds();
1537 13 : msg.WriteToLogFile();
1538 : }
1539 :
1540 291 : void Logger::ScriptEvent(ScriptEventType type, int script_id) {
1541 820 : if (!log_->IsEnabled() || !FLAG_log_function_events) return;
1542 53 : Log::MessageBuilder msg(log_);
1543 53 : msg << "script" << Logger::kNext;
1544 53 : switch (type) {
1545 : case ScriptEventType::kReserveId:
1546 13 : msg << "reserve-id";
1547 13 : break;
1548 : case ScriptEventType::kCreate:
1549 13 : msg << "create";
1550 13 : break;
1551 : case ScriptEventType::kDeserialize:
1552 27 : msg << "deserialize";
1553 27 : break;
1554 : case ScriptEventType::kBackgroundCompile:
1555 0 : msg << "background-compile";
1556 0 : break;
1557 : case ScriptEventType::kStreamingCompile:
1558 0 : msg << "streaming-compile";
1559 0 : break;
1560 : }
1561 106 : msg << Logger::kNext << script_id << Logger::kNext
1562 106 : << timer_.Elapsed().InMicroseconds();
1563 53 : msg.WriteToLogFile();
1564 : }
1565 :
1566 237 : void Logger::ScriptDetails(Script script) {
1567 711 : if (!log_->IsEnabled() || !FLAG_log_function_events) return;
1568 : {
1569 40 : Log::MessageBuilder msg(log_);
1570 80 : msg << "script-details" << Logger::kNext << script->id() << Logger::kNext;
1571 80 : if (script->name()->IsString()) {
1572 18 : msg << String::cast(script->name());
1573 : }
1574 80 : msg << Logger::kNext << script->line_offset() << Logger::kNext
1575 40 : << script->column_offset() << Logger::kNext;
1576 80 : if (script->source_mapping_url()->IsString()) {
1577 0 : msg << String::cast(script->source_mapping_url());
1578 : }
1579 40 : msg.WriteToLogFile();
1580 : }
1581 40 : EnsureLogScriptSource(script);
1582 : }
1583 :
1584 40 : bool Logger::EnsureLogScriptSource(Script script) {
1585 80 : if (!log_->IsEnabled()) return false;
1586 40 : Log::MessageBuilder msg(log_);
1587 : // Make sure the script is written to the log file.
1588 40 : int script_id = script->id();
1589 40 : if (logged_source_code_.find(script_id) != logged_source_code_.end()) {
1590 : return true;
1591 : }
1592 : // This script has not been logged yet.
1593 : logged_source_code_.insert(script_id);
1594 40 : Object source_object = script->source();
1595 40 : if (!source_object->IsString()) return false;
1596 40 : String source_code = String::cast(source_object);
1597 80 : msg << "script-source" << kNext << script_id << kNext;
1598 :
1599 : // Log the script name.
1600 80 : if (script->name()->IsString()) {
1601 18 : msg << String::cast(script->name()) << kNext;
1602 : } else {
1603 31 : msg << "<unknown>" << kNext;
1604 : }
1605 :
1606 : // Log the source code.
1607 40 : msg << source_code;
1608 40 : msg.WriteToLogFile();
1609 40 : return true;
1610 : }
1611 :
1612 0 : void Logger::RuntimeCallTimerEvent() {
1613 0 : RuntimeCallStats* stats = isolate_->counters()->runtime_call_stats();
1614 0 : RuntimeCallCounter* counter = stats->current_counter();
1615 0 : if (counter == nullptr) return;
1616 0 : Log::MessageBuilder msg(log_);
1617 0 : msg << "active-runtime-timer" << kNext << counter->name();
1618 0 : msg.WriteToLogFile();
1619 : }
1620 :
1621 0 : void Logger::TickEvent(v8::TickSample* sample, bool overflow) {
1622 0 : if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
1623 0 : if (V8_UNLIKELY(FLAG_runtime_stats ==
1624 : v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE)) {
1625 0 : RuntimeCallTimerEvent();
1626 : }
1627 0 : Log::MessageBuilder msg(log_);
1628 0 : msg << kLogEventsNames[CodeEventListener::TICK_EVENT] << kNext
1629 0 : << reinterpret_cast<void*>(sample->pc) << kNext
1630 0 : << timer_.Elapsed().InMicroseconds();
1631 0 : if (sample->has_external_callback) {
1632 0 : msg << kNext << 1 << kNext
1633 0 : << reinterpret_cast<void*>(sample->external_callback_entry);
1634 : } else {
1635 0 : msg << kNext << 0 << kNext << reinterpret_cast<void*>(sample->tos);
1636 : }
1637 0 : msg << kNext << static_cast<int>(sample->state);
1638 0 : if (overflow) msg << kNext << "overflow";
1639 0 : for (unsigned i = 0; i < sample->frames_count; ++i) {
1640 0 : msg << kNext << reinterpret_cast<void*>(sample->stack[i]);
1641 : }
1642 0 : msg.WriteToLogFile();
1643 : }
1644 :
1645 0 : void Logger::ICEvent(const char* type, bool keyed, Map map, Object key,
1646 : char old_state, char new_state, const char* modifier,
1647 : const char* slow_stub_reason) {
1648 0 : if (!log_->IsEnabled() || !FLAG_trace_ic) return;
1649 0 : Log::MessageBuilder msg(log_);
1650 0 : if (keyed) msg << "Keyed";
1651 : int line;
1652 : int column;
1653 0 : Address pc = isolate_->GetAbstractPC(&line, &column);
1654 0 : msg << type << kNext << reinterpret_cast<void*>(pc) << kNext << line << kNext
1655 0 : << column << kNext << old_state << kNext << new_state << kNext
1656 0 : << reinterpret_cast<void*>(map.ptr()) << kNext;
1657 0 : if (key->IsSmi()) {
1658 0 : msg << Smi::ToInt(key);
1659 0 : } else if (key->IsNumber()) {
1660 0 : msg << key->Number();
1661 0 : } else if (key->IsName()) {
1662 0 : msg << Name::cast(key);
1663 : }
1664 0 : msg << kNext << modifier << kNext;
1665 0 : if (slow_stub_reason != nullptr) {
1666 0 : msg << slow_stub_reason;
1667 : }
1668 0 : msg.WriteToLogFile();
1669 : }
1670 :
1671 7172 : void Logger::MapEvent(const char* type, Map from, Map to, const char* reason,
1672 : HeapObject name_or_sfi) {
1673 : DisallowHeapAllocation no_gc;
1674 14344 : if (!log_->IsEnabled() || !FLAG_trace_maps) return;
1675 7172 : if (!to.is_null()) MapDetails(to);
1676 7172 : int line = -1;
1677 7172 : int column = -1;
1678 : Address pc = 0;
1679 :
1680 7172 : if (!isolate_->bootstrapper()->IsActive()) {
1681 3747 : pc = isolate_->GetAbstractPC(&line, &column);
1682 : }
1683 7172 : Log::MessageBuilder msg(log_);
1684 14344 : msg << "map" << kNext << type << kNext << timer_.Elapsed().InMicroseconds()
1685 14344 : << kNext << reinterpret_cast<void*>(from.ptr()) << kNext
1686 14344 : << reinterpret_cast<void*>(to.ptr()) << kNext
1687 21516 : << reinterpret_cast<void*>(pc) << kNext << line << kNext << column
1688 14344 : << kNext << reason << kNext;
1689 :
1690 7172 : if (!name_or_sfi.is_null()) {
1691 5180 : if (name_or_sfi->IsName()) {
1692 5180 : msg << Name::cast(name_or_sfi);
1693 0 : } else if (name_or_sfi->IsSharedFunctionInfo()) {
1694 0 : SharedFunctionInfo sfi = SharedFunctionInfo::cast(name_or_sfi);
1695 0 : msg << sfi->DebugName();
1696 : #if V8_SFI_HAS_UNIQUE_ID
1697 : msg << " " << sfi->unique_id();
1698 : #endif // V8_SFI_HAS_UNIQUE_ID
1699 : }
1700 : }
1701 7172 : msg.WriteToLogFile();
1702 : }
1703 :
1704 15867 : void Logger::MapCreate(Map map) {
1705 31734 : if (!log_->IsEnabled() || !FLAG_trace_maps) return;
1706 : DisallowHeapAllocation no_gc;
1707 15867 : Log::MessageBuilder msg(log_);
1708 47601 : msg << "map-create" << kNext << timer_.Elapsed().InMicroseconds() << kNext
1709 31734 : << reinterpret_cast<void*>(map.ptr());
1710 15867 : msg.WriteToLogFile();
1711 : }
1712 :
1713 15955 : void Logger::MapDetails(Map map) {
1714 31998 : if (!log_->IsEnabled() || !FLAG_trace_maps) return;
1715 : DisallowHeapAllocation no_gc;
1716 15867 : Log::MessageBuilder msg(log_);
1717 47601 : msg << "map-details" << kNext << timer_.Elapsed().InMicroseconds() << kNext
1718 31734 : << reinterpret_cast<void*>(map.ptr()) << kNext;
1719 15867 : if (FLAG_trace_maps_details) {
1720 15867 : std::ostringstream buffer;
1721 15867 : map->PrintMapDetails(buffer);
1722 31734 : msg << buffer.str().c_str();
1723 : }
1724 15867 : msg.WriteToLogFile();
1725 : }
1726 :
1727 0 : void Logger::StopProfiler() {
1728 0 : if (!log_->IsEnabled()) return;
1729 0 : if (profiler_ != nullptr) {
1730 : profiler_->Pause();
1731 0 : is_logging_ = false;
1732 0 : RemoveCodeEventListener(this);
1733 : }
1734 : }
1735 :
1736 : // This function can be called when Log's mutex is acquired,
1737 : // either from main or Profiler's thread.
1738 0 : void Logger::LogFailure() {
1739 0 : StopProfiler();
1740 0 : }
1741 :
1742 2221532 : static void AddFunctionAndCode(SharedFunctionInfo sfi, AbstractCode code_object,
1743 : Handle<SharedFunctionInfo>* sfis,
1744 : Handle<AbstractCode>* code_objects, int offset) {
1745 2221532 : if (sfis != nullptr) {
1746 2221532 : sfis[offset] = Handle<SharedFunctionInfo>(sfi, sfi->GetIsolate());
1747 : }
1748 2221532 : if (code_objects != nullptr) {
1749 2221532 : code_objects[offset] = Handle<AbstractCode>(code_object, sfi->GetIsolate());
1750 : }
1751 2221532 : }
1752 :
1753 1576 : static int EnumerateCompiledFunctions(Heap* heap,
1754 : Handle<SharedFunctionInfo>* sfis,
1755 : Handle<AbstractCode>* code_objects) {
1756 1576 : HeapIterator iterator(heap);
1757 : DisallowHeapAllocation no_gc;
1758 : int compiled_funcs_count = 0;
1759 :
1760 : // Iterate the heap to find shared function info objects and record
1761 : // the unoptimized code for them.
1762 46948680 : for (HeapObject obj = iterator.next(); !obj.is_null();
1763 : obj = iterator.next()) {
1764 23472764 : if (obj->IsSharedFunctionInfo()) {
1765 2035274 : SharedFunctionInfo sfi = SharedFunctionInfo::cast(obj);
1766 6105822 : if (sfi->is_compiled() &&
1767 7082950 : (!sfi->script()->IsScript() ||
1768 4046626 : Script::cast(sfi->script())->HasValidSource())) {
1769 : AddFunctionAndCode(sfi, AbstractCode::cast(sfi->abstract_code()), sfis,
1770 4041960 : code_objects, compiled_funcs_count);
1771 2020980 : ++compiled_funcs_count;
1772 : }
1773 21437490 : } else if (obj->IsJSFunction()) {
1774 : // Given that we no longer iterate over all optimized JSFunctions, we need
1775 : // to take care of this here.
1776 2001070 : JSFunction function = JSFunction::cast(obj);
1777 4002140 : SharedFunctionInfo sfi = SharedFunctionInfo::cast(function->shared());
1778 2001070 : Object maybe_script = sfi->script();
1779 6003210 : if (maybe_script->IsScript() &&
1780 4040750 : !Script::cast(maybe_script)->HasValidSource()) {
1781 20 : continue;
1782 : }
1783 : // TODO(jarin) This leaves out deoptimized code that might still be on the
1784 : // stack. Also note that we will not log optimized code objects that are
1785 : // only on a type feedback vector. We should make this mroe precise.
1786 2001050 : if (function->IsOptimized()) {
1787 : AddFunctionAndCode(sfi, AbstractCode::cast(function->code()), sfis,
1788 401104 : code_objects, compiled_funcs_count);
1789 200552 : ++compiled_funcs_count;
1790 : }
1791 : }
1792 : }
1793 1576 : return compiled_funcs_count;
1794 : }
1795 :
1796 1576 : static int EnumerateWasmModuleObjects(
1797 : Heap* heap, Handle<WasmModuleObject>* module_objects) {
1798 1576 : HeapIterator iterator(heap);
1799 : DisallowHeapAllocation no_gc;
1800 : int module_objects_count = 0;
1801 :
1802 46950488 : for (HeapObject obj = iterator.next(); !obj.is_null();
1803 : obj = iterator.next()) {
1804 23473668 : if (obj->IsWasmModuleObject()) {
1805 : WasmModuleObject module = WasmModuleObject::cast(obj);
1806 0 : if (module_objects != nullptr) {
1807 0 : module_objects[module_objects_count] = handle(module, heap->isolate());
1808 : }
1809 0 : module_objects_count++;
1810 : }
1811 : }
1812 1576 : return module_objects_count;
1813 : }
1814 :
1815 0 : void Logger::LogCodeObject(Object object) {
1816 0 : existing_code_logger_.LogCodeObject(object);
1817 0 : }
1818 :
1819 35 : void Logger::LogCodeObjects() { existing_code_logger_.LogCodeObjects(); }
1820 :
1821 0 : void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
1822 : Handle<AbstractCode> code) {
1823 0 : existing_code_logger_.LogExistingFunction(shared, code);
1824 0 : }
1825 :
1826 763 : void Logger::LogCompiledFunctions() {
1827 768 : existing_code_logger_.LogCompiledFunctions();
1828 763 : }
1829 :
1830 748 : void Logger::LogAccessorCallbacks() {
1831 748 : Heap* heap = isolate_->heap();
1832 748 : HeapIterator iterator(heap);
1833 : DisallowHeapAllocation no_gc;
1834 22919422 : for (HeapObject obj = iterator.next(); !obj.is_null();
1835 : obj = iterator.next()) {
1836 22909083 : if (!obj->IsAccessorInfo()) continue;
1837 8843 : AccessorInfo ai = AccessorInfo::cast(obj);
1838 17686 : if (!ai->name()->IsName()) continue;
1839 8843 : Address getter_entry = v8::ToCData<Address>(ai->getter());
1840 17686 : Name name = Name::cast(ai->name());
1841 8843 : if (getter_entry != 0) {
1842 : #if USES_FUNCTION_DESCRIPTORS
1843 : getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(getter_entry);
1844 : #endif
1845 17686 : PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
1846 : }
1847 8843 : Address setter_entry = v8::ToCData<Address>(ai->setter());
1848 8843 : if (setter_entry != 0) {
1849 : #if USES_FUNCTION_DESCRIPTORS
1850 : setter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(setter_entry);
1851 : #endif
1852 17676 : PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
1853 : }
1854 748 : }
1855 748 : }
1856 :
1857 17 : void Logger::LogAllMaps() {
1858 : DisallowHeapAllocation no_gc;
1859 17 : Heap* heap = isolate_->heap();
1860 17 : HeapIterator iterator(heap);
1861 168436 : for (HeapObject obj = iterator.next(); !obj.is_null();
1862 : obj = iterator.next()) {
1863 165784 : if (!obj->IsMap()) continue;
1864 2618 : Map map = Map::cast(obj);
1865 2618 : MapCreate(map);
1866 2618 : MapDetails(map);
1867 17 : }
1868 17 : }
1869 :
1870 62883 : static void AddIsolateIdIfNeeded(std::ostream& os, // NOLINT
1871 : Isolate* isolate) {
1872 62883 : if (FLAG_logfile_per_isolate) {
1873 66758 : os << "isolate-" << isolate << "-" << base::OS::GetCurrentProcessId()
1874 33379 : << "-";
1875 : }
1876 62883 : }
1877 :
1878 62883 : static void PrepareLogFileName(std::ostream& os, // NOLINT
1879 : Isolate* isolate, const char* file_name) {
1880 : int dir_separator_count = 0;
1881 439876 : for (const char* p = file_name; *p; p++) {
1882 376993 : if (base::OS::isDirectorySeparator(*p)) dir_separator_count++;
1883 : }
1884 :
1885 376993 : for (const char* p = file_name; *p; p++) {
1886 376993 : if (dir_separator_count == 0) {
1887 62883 : AddIsolateIdIfNeeded(os, isolate);
1888 62883 : dir_separator_count--;
1889 : }
1890 376993 : if (*p == '%') {
1891 0 : p++;
1892 0 : switch (*p) {
1893 : case '\0':
1894 : // If there's a % at the end of the string we back up
1895 : // one character so we can escape the loop properly.
1896 : p--;
1897 : break;
1898 : case 'p':
1899 0 : os << base::OS::GetCurrentProcessId();
1900 0 : break;
1901 : case 't':
1902 : // %t expands to the current time in milliseconds.
1903 : os << static_cast<int64_t>(
1904 0 : V8::GetCurrentPlatform()->CurrentClockTimeMillis());
1905 : break;
1906 : case '%':
1907 : // %% expands (contracts really) to %.
1908 : os << '%';
1909 : break;
1910 : default:
1911 : // All other %'s expand to themselves.
1912 : os << '%' << *p;
1913 : break;
1914 : }
1915 : } else {
1916 376993 : if (base::OS::isDirectorySeparator(*p)) dir_separator_count--;
1917 376993 : os << *p;
1918 : }
1919 : }
1920 62883 : }
1921 :
1922 :
1923 62883 : bool Logger::SetUp(Isolate* isolate) {
1924 : // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
1925 62883 : if (is_initialized_) return true;
1926 62883 : is_initialized_ = true;
1927 :
1928 62883 : std::ostringstream log_file_name;
1929 125766 : std::ostringstream source_log_file_name;
1930 62883 : PrepareLogFileName(log_file_name, isolate, FLAG_logfile);
1931 125766 : log_ = new Log(this, log_file_name.str().c_str());
1932 :
1933 62883 : if (FLAG_perf_basic_prof) {
1934 0 : perf_basic_logger_ = new PerfBasicLogger(isolate);
1935 0 : AddCodeEventListener(perf_basic_logger_);
1936 : }
1937 :
1938 62883 : if (FLAG_perf_prof) {
1939 0 : perf_jit_logger_ = new PerfJitLogger(isolate);
1940 0 : AddCodeEventListener(perf_jit_logger_);
1941 : }
1942 :
1943 62883 : if (FLAG_ll_prof) {
1944 0 : ll_logger_ = new LowLevelLogger(isolate, log_file_name.str().c_str());
1945 0 : AddCodeEventListener(ll_logger_);
1946 : }
1947 :
1948 62883 : ticker_ = new Ticker(isolate, FLAG_prof_sampling_interval);
1949 :
1950 62883 : if (Log::InitLogAtStart()) {
1951 61 : is_logging_ = true;
1952 : }
1953 :
1954 : timer_.Start();
1955 :
1956 62883 : if (FLAG_prof_cpp) {
1957 0 : profiler_ = new Profiler(isolate);
1958 0 : is_logging_ = true;
1959 0 : profiler_->Engage();
1960 : }
1961 :
1962 62883 : if (is_logging_) {
1963 61 : AddCodeEventListener(this);
1964 : }
1965 :
1966 62883 : return true;
1967 : }
1968 :
1969 :
1970 60 : void Logger::SetCodeEventHandler(uint32_t options,
1971 : JitCodeEventHandler event_handler) {
1972 60 : if (jit_logger_) {
1973 : RemoveCodeEventListener(jit_logger_);
1974 25 : delete jit_logger_;
1975 25 : jit_logger_ = nullptr;
1976 : }
1977 :
1978 60 : if (event_handler) {
1979 35 : jit_logger_ = new JitLogger(isolate_, event_handler);
1980 35 : AddCodeEventListener(jit_logger_);
1981 35 : if (options & kJitCodeEventEnumExisting) {
1982 5 : HandleScope scope(isolate_);
1983 : LogCodeObjects();
1984 : LogCompiledFunctions();
1985 : }
1986 : }
1987 60 : }
1988 :
1989 62867 : sampler::Sampler* Logger::sampler() {
1990 62867 : return ticker_;
1991 : }
1992 :
1993 125734 : void Logger::StopProfilerThread() {
1994 125734 : if (profiler_ != nullptr) {
1995 0 : profiler_->Disengage();
1996 0 : delete profiler_;
1997 0 : profiler_ = nullptr;
1998 : }
1999 125734 : }
2000 :
2001 62985 : FILE* Logger::TearDown() {
2002 62985 : if (!is_initialized_) return nullptr;
2003 62868 : is_initialized_ = false;
2004 :
2005 : // Stop the profiler thread before closing the file.
2006 62868 : StopProfilerThread();
2007 :
2008 62868 : delete ticker_;
2009 62868 : ticker_ = nullptr;
2010 :
2011 62868 : if (perf_basic_logger_) {
2012 : RemoveCodeEventListener(perf_basic_logger_);
2013 0 : delete perf_basic_logger_;
2014 0 : perf_basic_logger_ = nullptr;
2015 : }
2016 :
2017 62868 : if (perf_jit_logger_) {
2018 : RemoveCodeEventListener(perf_jit_logger_);
2019 0 : delete perf_jit_logger_;
2020 0 : perf_jit_logger_ = nullptr;
2021 : }
2022 :
2023 62868 : if (ll_logger_) {
2024 : RemoveCodeEventListener(ll_logger_);
2025 0 : delete ll_logger_;
2026 0 : ll_logger_ = nullptr;
2027 : }
2028 :
2029 62868 : if (jit_logger_) {
2030 : RemoveCodeEventListener(jit_logger_);
2031 10 : delete jit_logger_;
2032 10 : jit_logger_ = nullptr;
2033 : }
2034 :
2035 62868 : return log_->Close();
2036 : }
2037 :
2038 83181 : void ExistingCodeLogger::LogCodeObject(Object object) {
2039 83181 : AbstractCode abstract_code = AbstractCode::cast(object);
2040 : CodeEventListener::LogEventsAndTags tag = CodeEventListener::STUB_TAG;
2041 : const char* description = "Unknown code from before profiling";
2042 83181 : switch (abstract_code->kind()) {
2043 : case AbstractCode::INTERPRETED_FUNCTION:
2044 : case AbstractCode::OPTIMIZED_FUNCTION:
2045 26244 : return; // We log this later using LogCompiledFunctions.
2046 : case AbstractCode::BYTECODE_HANDLER:
2047 : return; // We log it later by walking the dispatch table.
2048 : case AbstractCode::STUB:
2049 : description = "STUB code";
2050 : tag = CodeEventListener::STUB_TAG;
2051 12 : break;
2052 : case AbstractCode::REGEXP:
2053 : description = "Regular expression code";
2054 : tag = CodeEventListener::REG_EXP_TAG;
2055 0 : break;
2056 : case AbstractCode::BUILTIN:
2057 114265 : if (Code::cast(object)->is_interpreter_trampoline_builtin() &&
2058 : Code::cast(object) !=
2059 57220 : *BUILTIN_CODE(isolate_, InterpreterEntryTrampoline)) {
2060 : return;
2061 : }
2062 : description =
2063 113850 : isolate_->builtins()->name(abstract_code->GetCode()->builtin_index());
2064 : tag = CodeEventListener::BUILTIN_TAG;
2065 56925 : break;
2066 : case AbstractCode::WASM_FUNCTION:
2067 : description = "A Wasm function";
2068 : tag = CodeEventListener::FUNCTION_TAG;
2069 0 : break;
2070 : case AbstractCode::JS_TO_WASM_FUNCTION:
2071 : description = "A JavaScript to Wasm adapter";
2072 : tag = CodeEventListener::STUB_TAG;
2073 0 : break;
2074 : case AbstractCode::WASM_TO_JS_FUNCTION:
2075 : description = "A Wasm to JavaScript adapter";
2076 : tag = CodeEventListener::STUB_TAG;
2077 0 : break;
2078 : case AbstractCode::WASM_INTERPRETER_ENTRY:
2079 : description = "A Wasm to Interpreter adapter";
2080 : tag = CodeEventListener::STUB_TAG;
2081 0 : break;
2082 : case AbstractCode::C_WASM_ENTRY:
2083 : description = "A C to Wasm entry stub";
2084 : tag = CodeEventListener::STUB_TAG;
2085 0 : break;
2086 : case AbstractCode::NUMBER_OF_KINDS:
2087 0 : UNIMPLEMENTED();
2088 : }
2089 93168 : CALL_CODE_EVENT_HANDLER(CodeCreateEvent(tag, abstract_code, description))
2090 : }
2091 :
2092 55 : void ExistingCodeLogger::LogCodeObjects() {
2093 55 : Heap* heap = isolate_->heap();
2094 55 : HeapIterator iterator(heap);
2095 : DisallowHeapAllocation no_gc;
2096 782050 : for (HeapObject obj = iterator.next(); !obj.is_null();
2097 : obj = iterator.next()) {
2098 390970 : if (obj->IsCode()) LogCodeObject(obj);
2099 390970 : if (obj->IsBytecodeArray()) LogCodeObject(obj);
2100 55 : }
2101 55 : }
2102 :
2103 788 : void ExistingCodeLogger::LogCompiledFunctions() {
2104 788 : Heap* heap = isolate_->heap();
2105 : HandleScope scope(isolate_);
2106 : const int compiled_funcs_count =
2107 788 : EnumerateCompiledFunctions(heap, nullptr, nullptr);
2108 : ScopedVector<Handle<SharedFunctionInfo>> sfis(compiled_funcs_count);
2109 : ScopedVector<Handle<AbstractCode>> code_objects(compiled_funcs_count);
2110 788 : EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
2111 :
2112 : // During iteration, there can be heap allocation due to
2113 : // GetScriptLineNumber call.
2114 1111554 : for (int i = 0; i < compiled_funcs_count; ++i) {
2115 3332298 : if (sfis[i]->function_data()->IsInterpreterData()) {
2116 : LogExistingFunction(
2117 : sfis[i],
2118 : Handle<AbstractCode>(
2119 24 : AbstractCode::cast(sfis[i]->InterpreterTrampoline()), isolate_),
2120 24 : CodeEventListener::INTERPRETED_FUNCTION_TAG);
2121 : }
2122 2221532 : if (code_objects[i].is_identical_to(BUILTIN_CODE(isolate_, CompileLazy)))
2123 : continue;
2124 1110766 : LogExistingFunction(sfis[i], code_objects[i]);
2125 : }
2126 :
2127 : const int wasm_module_objects_count =
2128 788 : EnumerateWasmModuleObjects(heap, nullptr);
2129 : std::unique_ptr<Handle<WasmModuleObject>[]> module_objects(
2130 788 : new Handle<WasmModuleObject>[wasm_module_objects_count]);
2131 788 : EnumerateWasmModuleObjects(heap, module_objects.get());
2132 788 : for (int i = 0; i < wasm_module_objects_count; ++i) {
2133 0 : module_objects[i]->native_module()->LogWasmCodes(isolate_);
2134 : }
2135 788 : }
2136 :
2137 1110778 : void ExistingCodeLogger::LogExistingFunction(
2138 : Handle<SharedFunctionInfo> shared, Handle<AbstractCode> code,
2139 : CodeEventListener::LogEventsAndTags tag) {
2140 2221556 : if (shared->script()->IsScript()) {
2141 1809348 : Handle<Script> script(Script::cast(shared->script()), isolate_);
2142 603116 : int line_num = Script::GetLineNumber(script, shared->StartPosition()) + 1;
2143 : int column_num =
2144 603116 : Script::GetColumnNumber(script, shared->StartPosition()) + 1;
2145 1206232 : if (script->name()->IsString()) {
2146 2535 : Handle<String> script_name(String::cast(script->name()), isolate_);
2147 845 : if (line_num > 0) {
2148 3380 : CALL_CODE_EVENT_HANDLER(
2149 : CodeCreateEvent(Logger::ToNativeByScript(tag, *script), *code,
2150 : *shared, *script_name, line_num, column_num))
2151 : } else {
2152 : // Can't distinguish eval and script here, so always use Script.
2153 0 : CALL_CODE_EVENT_HANDLER(CodeCreateEvent(
2154 : Logger::ToNativeByScript(CodeEventListener::SCRIPT_TAG, *script),
2155 : *code, *shared, *script_name))
2156 : }
2157 : } else {
2158 2409028 : CALL_CODE_EVENT_HANDLER(CodeCreateEvent(
2159 : Logger::ToNativeByScript(tag, *script), *code, *shared,
2160 : ReadOnlyRoots(isolate_).empty_string(), line_num, column_num))
2161 : }
2162 507662 : } else if (shared->IsApiFunction()) {
2163 : // API function.
2164 19277 : FunctionTemplateInfo fun_data = shared->get_api_func_data();
2165 19277 : Object raw_call_data = fun_data->call_code();
2166 38554 : if (!raw_call_data->IsUndefined(isolate_)) {
2167 19187 : CallHandlerInfo call_data = CallHandlerInfo::cast(raw_call_data);
2168 19187 : Object callback_obj = call_data->callback();
2169 19187 : Address entry_point = v8::ToCData<Address>(callback_obj);
2170 : #if USES_FUNCTION_DESCRIPTORS
2171 : entry_point = *FUNCTION_ENTRYPOINT_ADDRESS(entry_point);
2172 : #endif
2173 57141 : CALL_CODE_EVENT_HANDLER(CallbackEvent(shared->DebugName(), entry_point))
2174 : }
2175 : }
2176 1110778 : }
2177 :
2178 : #undef CALL_CODE_EVENT_HANDLER
2179 :
2180 : } // namespace internal
2181 183867 : } // namespace v8
|