• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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