1 // Copyright 2010 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/diagnostics/system-jit-win.h"
6
7 #include "include/v8-callbacks.h"
8 #include "include/v8-isolate.h"
9 #include "include/v8-local-handle.h"
10 #include "include/v8-primitive.h"
11 #include "include/v8-script.h"
12 #include "src/api/api-inl.h"
13 #include "src/base/lazy-instance.h"
14 #include "src/base/logging.h"
15 #include "src/diagnostics/system-jit-metadata-win.h"
16 #include "src/libplatform/tracing/recorder.h"
17 #include "src/objects/shared-function-info.h"
18
19 #if !defined(V8_ENABLE_SYSTEM_INSTRUMENTATION)
20 #error "This file is only compiled if v8_enable_system_instrumentation"
21 #endif
22
23 #if defined(__clang__)
24 #pragma clang diagnostic ignored "-Wc++98-compat-extra-semi"
25 #endif
26
27 namespace v8 {
28 namespace internal {
29 namespace ETWJITInterface {
30
31 TRACELOGGING_DECLARE_PROVIDER(g_v8Provider);
32
33 TRACELOGGING_DEFINE_PROVIDER(g_v8Provider, "V8.js", (V8_ETW_GUID));
34
35 using ScriptMapType = std::unordered_set<int>;
36 static base::LazyInstance<ScriptMapType>::type script_map =
37 LAZY_INSTANCE_INITIALIZER;
38
39 // TODO(v8/11911): UnboundScript::GetLineNumber should be replaced
GetSharedFunctionInfo(const JitCodeEvent * event)40 SharedFunctionInfo GetSharedFunctionInfo(const JitCodeEvent* event) {
41 return event->script.IsEmpty() ? SharedFunctionInfo()
42 : *Utils::OpenHandle(*event->script);
43 }
44
GetScriptLineNumber(const JitCodeEvent * event)45 int GetScriptLineNumber(const JitCodeEvent* event) {
46 auto sfi = GetSharedFunctionInfo(event);
47 return sfi.is_null()
48 ? -1 // invalid sentinel number
49 : Script::cast(sfi.script()).GetLineNumber(sfi.StartPosition()) +
50 1;
51 }
52
Register()53 void Register() {
54 DCHECK(!TraceLoggingProviderEnabled(g_v8Provider, 0, 0));
55 TraceLoggingRegister(g_v8Provider);
56 }
57
Unregister()58 void Unregister() {
59 if (g_v8Provider) {
60 TraceLoggingUnregister(g_v8Provider);
61 }
62 }
63
EventHandler(const JitCodeEvent * event)64 void EventHandler(const JitCodeEvent* event) {
65 if (event->code_type != v8::JitCodeEvent::CodeType::JIT_CODE) return;
66 if (event->type != v8::JitCodeEvent::EventType::CODE_ADDED) return;
67
68 int name_len = static_cast<int>(event->name.len);
69 // Note: event->name.str is not null terminated.
70 std::wstring method_name(name_len + 1, '\0');
71 MultiByteToWideChar(
72 CP_UTF8, 0, event->name.str, name_len,
73 // Const cast needed as building with C++14 (not const in >= C++17)
74 const_cast<LPWSTR>(method_name.data()),
75 static_cast<int>(method_name.size()));
76
77 v8::Isolate* script_context = event->isolate;
78 v8::Local<v8::UnboundScript> script = event->script;
79 int script_id = 0;
80 if (!script.IsEmpty()) {
81 // if the first time seeing this source file, log the SourceLoad event
82 script_id = script->GetId();
83 if (script_map.Pointer()->find(script_id) == script_map.Pointer()->end()) {
84 script_map.Pointer()->insert(script_id);
85
86 v8::Local<v8::Value> script_name = script->GetScriptName();
87 std::wstring wstr_name(0, L'\0');
88 if (script_name->IsString()) {
89 auto v8str_name = script_name.As<v8::String>();
90 wstr_name.resize(v8str_name->Length());
91 // On Windows wchar_t == uint16_t. const_Cast needed for C++14.
92 uint16_t* wstr_data = const_cast<uint16_t*>(
93 reinterpret_cast<const uint16_t*>(wstr_name.data()));
94 v8str_name->Write(event->isolate, wstr_data);
95 }
96
97 constexpr static auto source_load_event_meta =
98 EventMetadata(kSourceLoadEventID, kJScriptRuntimeKeyword);
99 constexpr static auto source_load_event_fields = EventFields(
100 "SourceLoad", Field("SourceID", TlgInUINT64),
101 Field("ScriptContextID", TlgInPOINTER),
102 Field("SourceFlags", TlgInUINT32), Field("Url", TlgInUNICODESTRING));
103 LogEventData(g_v8Provider, &source_load_event_meta,
104 &source_load_event_fields, (uint64_t)script_id,
105 script_context,
106 (uint32_t)0, // SourceFlags
107 wstr_name);
108 }
109 }
110
111 constexpr static auto method_load_event_meta =
112 EventMetadata(kMethodLoadEventID, kJScriptRuntimeKeyword);
113 constexpr static auto method_load_event_fields = EventFields(
114 "MethodLoad", Field("ScriptContextID", TlgInPOINTER),
115 Field("MethodStartAddress", TlgInPOINTER),
116 Field("MethodSize", TlgInUINT64), Field("MethodID", TlgInUINT32),
117 Field("MethodFlags", TlgInUINT16),
118 Field("MethodAddressRangeID", TlgInUINT16),
119 Field("SourceID", TlgInUINT64), Field("Line", TlgInUINT32),
120 Field("Column", TlgInUINT32), Field("MethodName", TlgInUNICODESTRING));
121
122 LogEventData(g_v8Provider, &method_load_event_meta, &method_load_event_fields,
123 script_context, event->code_start, (uint64_t)event->code_len,
124 (uint32_t)0, // MethodId
125 (uint16_t)0, // MethodFlags
126 (uint16_t)0, // MethodAddressRangeId
127 (uint64_t)script_id, (uint32_t)GetScriptLineNumber(event),
128 (uint32_t)0, // Line & Column
129 method_name);
130 }
131
132 } // namespace ETWJITInterface
133 } // namespace internal
134 } // namespace v8
135