v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
code-data-source.cc
Go to the documentation of this file.
1// Copyright 2024 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
6
7#include "protos/perfetto/common/data_source_descriptor.gen.h"
8#include "protos/perfetto/config/chrome/v8_config.gen.h"
9#include "protos/perfetto/trace/chrome/v8.pbzero.h"
11#include "src/handles/handles.h"
12#include "src/heap/code-range.h"
14#include "src/objects/script.h"
19
20#if V8_ENABLE_WEBASSEMBLY
22#endif // V8_ENABLE_WEBASSEMBLY
23
26
27namespace v8 {
28namespace internal {
29namespace {
30
31using ::perfetto::protos::gen::V8Config;
32using ::perfetto::protos::pbzero::InternedV8JsFunction;
33using ::perfetto::protos::pbzero::InternedV8JsScript;
34using ::perfetto::protos::pbzero::InternedV8String;
35using ::perfetto::protos::pbzero::TracePacket;
36
37InternedV8JsScript::Type GetJsScriptType(Tagged<Script> script) {
38 if (script->compilation_type() == Script::CompilationType::kEval) {
39 return InternedV8JsScript::TYPE_EVAL;
40 }
41
42 // TODO(carlscab): Camillo to extend the Script::Type enum. compilation_type
43 // will no longer be needed.
44
45 switch (script->type()) {
47 return InternedV8JsScript::TYPE_NATIVE;
49 return InternedV8JsScript::TYPE_EXTENSION;
51 return InternedV8JsScript::TYPE_NORMAL;
52#if V8_ENABLE_WEBASSEMBLY
53 case Script::Type::kWasm:
55#endif // V8_ENABLE_WEBASSEMBLY
57 return InternedV8JsScript::TYPE_INSPECTOR;
58 }
59}
60
61InternedV8JsFunction::Kind GetJsFunctionKind(FunctionKind kind) {
62 switch (kind) {
64 return InternedV8JsFunction::KIND_NORMAL_FUNCTION;
66 return InternedV8JsFunction::KIND_MODULE;
68 return InternedV8JsFunction::KIND_ASYNC_MODULE;
70 return InternedV8JsFunction::KIND_BASE_CONSTRUCTOR;
72 return InternedV8JsFunction::KIND_DEFAULT_BASE_CONSTRUCTOR;
74 return InternedV8JsFunction::KIND_DEFAULT_DERIVED_CONSTRUCTOR;
76 return InternedV8JsFunction::KIND_DERIVED_CONSTRUCTOR;
78 return InternedV8JsFunction::KIND_GETTER_FUNCTION;
80 return InternedV8JsFunction::KIND_STATIC_GETTER_FUNCTION;
82 return InternedV8JsFunction::KIND_SETTER_FUNCTION;
84 return InternedV8JsFunction::KIND_STATIC_SETTER_FUNCTION;
86 return InternedV8JsFunction::KIND_ARROW_FUNCTION;
88 return InternedV8JsFunction::KIND_ASYNC_ARROW_FUNCTION;
90 return InternedV8JsFunction::KIND_ASYNC_FUNCTION;
92 return InternedV8JsFunction::KIND_ASYNC_CONCISE_METHOD;
94 return InternedV8JsFunction::KIND_STATIC_ASYNC_CONCISE_METHOD;
96 return InternedV8JsFunction::KIND_ASYNC_CONCISE_GENERATOR_METHOD;
98 return InternedV8JsFunction::KIND_STATIC_ASYNC_CONCISE_GENERATOR_METHOD;
100 return InternedV8JsFunction::KIND_ASYNC_GENERATOR_FUNCTION;
102 return InternedV8JsFunction::KIND_GENERATOR_FUNCTION;
104 return InternedV8JsFunction::KIND_CONCISE_GENERATOR_METHOD;
106 return InternedV8JsFunction::KIND_STATIC_CONCISE_GENERATOR_METHOD;
108 return InternedV8JsFunction::KIND_CONCISE_METHOD;
110 return InternedV8JsFunction::KIND_STATIC_CONCISE_METHOD;
112 return InternedV8JsFunction::KIND_CLASS_MEMBERS_INITIALIZER_FUNCTION;
114 return InternedV8JsFunction::KIND_CLASS_STATIC_INITIALIZER_FUNCTION;
116 return InternedV8JsFunction::KIND_INVALID;
117 }
118
119 return InternedV8JsFunction::KIND_UNKNOWN;
120}
121
122} // namespace
123
125 const CodeDataSource::TraceContext& context) {
126 if (auto ds = context.GetDataSourceLocked(); ds) {
127 const V8Config& config = ds->config();
128 log_script_sources_ = config.log_script_sources();
129 log_instructions_ = config.log_instructions();
130 }
131 initialized_ = true;
132}
133
135 CodeDataSource::TraceContext::TracePacketHandle& packet) {
136 auto ranges = serialized_interned_data_.GetRanges();
137 packet->AppendScatteredBytes(TracePacket::kInternedDataFieldNumber,
138 &ranges[0], ranges.size());
140}
141
143 auto [it, was_inserted] = isolates_.emplace(isolate.id(), next_isolate_iid());
144 uint64_t iid = it->second;
145 if (!was_inserted) {
146 return iid;
147 }
148
149 auto* isolate_proto = serialized_interned_data_->add_v8_isolate();
150 isolate_proto->set_iid(iid);
151 isolate_proto->set_isolate_id(isolate.id());
152 isolate_proto->set_pid(base::OS::GetCurrentProcessId());
153 isolate_proto->set_embedded_blob_code_start_address(
154 reinterpret_cast<uint64_t>(isolate.embedded_blob_code()));
155 isolate_proto->set_embedded_blob_code_size(isolate.embedded_blob_code_size());
156 if (auto* code_range = isolate.heap()->code_range(); code_range != nullptr) {
157 auto* v8_code_range = isolate_proto->set_code_range();
158 v8_code_range->set_base_address(code_range->base());
159 v8_code_range->set_size(code_range->size());
160 if (code_range == IsolateGroup::current()->GetCodeRange()) {
161 // FIXME(42204573): Belongs to isolate group, not process.
162 v8_code_range->set_is_process_wide(true);
163 }
164 if (auto* embedded_builtins_start = code_range->embedded_blob_code_copy();
165 embedded_builtins_start != nullptr) {
166 v8_code_range->set_embedded_blob_code_copy_start_address(
167 reinterpret_cast<uint64_t>(embedded_builtins_start));
168 }
169 }
170
171 return iid;
172}
173
175 Tagged<Script> script) {
176 auto [it, was_inserted] = scripts_.emplace(
178 script->id()},
180 uint64_t iid = it->second;
181 if (!was_inserted) {
182 return iid;
183 }
184
185 auto* proto = serialized_interned_data_->add_v8_js_script();
186 proto->set_iid(iid);
187 proto->set_script_id(script->id());
188 proto->set_type(GetJsScriptType(script));
189 if (IsString(script->name())) {
190 PerfettoV8String(Cast<String>(script->name()))
191 .WriteToProto(*proto->set_name());
192 }
193 if (log_script_sources() && IsString(script->source())) {
194 PerfettoV8String(Cast<String>(script->source()))
195 .WriteToProto(*proto->set_source());
196 }
197
198 return iid;
199}
200
203 uint64_t v8_js_script_iid, int line_num, int column_num) {
204 DirectHandle<String> function_name =
205 SharedFunctionInfo::DebugName(&isolate, info);
206 uint64_t v8_js_function_name_iid = InternJsFunctionName(*function_name);
207
208 auto [it, was_inserted] = functions_.emplace(
210 v8_js_script_iid, info->is_toplevel(), info->StartPosition()},
212 const uint64_t iid = it->second;
213 if (!was_inserted) {
214 return iid;
215 }
216
217 auto* function_proto = serialized_interned_data_->add_v8_js_function();
218 function_proto->set_iid(iid);
219 function_proto->set_v8_js_function_name_iid(v8_js_function_name_iid);
220 function_proto->set_v8_js_script_iid(v8_js_script_iid);
221 function_proto->set_kind(GetJsFunctionKind(info->kind()));
222 int32_t start_position = info->StartPosition();
223 if (start_position >= 0) {
224 function_proto->set_byte_offset(static_cast<uint32_t>(start_position));
225 }
226 if (line_num > 0 && column_num > 0) {
227 function_proto->set_line(static_cast<uint32_t>(line_num));
228 function_proto->set_column(static_cast<uint32_t>(column_num));
229 }
230
231 return iid;
232}
233
234#if V8_ENABLE_WEBASSEMBLY
235uint64_t CodeDataSourceIncrementalState::InternWasmScript(
236 Isolate& isolate, int script_id, const std::string& url,
237 wasm::NativeModule* native_module) {
238 auto [it, was_inserted] = scripts_.emplace(
239 CodeDataSourceIncrementalState::ScriptUniqueId{isolate.id(), script_id},
241 uint64_t iid = it->second;
242 if (!was_inserted) {
243 return iid;
244 }
245
246 auto* script = serialized_interned_data_->add_v8_wasm_script();
247 script->set_iid(iid);
248 script->set_script_id(script_id);
249 script->set_url(url);
250 if (log_script_sources()) {
251 base::Vector<const uint8_t> bytes_vec = native_module->wire_bytes();
252 script->set_wire_bytes(bytes_vec.begin(), bytes_vec.size());
253 // TODO(carlscab): Log script source if needed.
254 }
255
256 return iid;
257}
258#endif // V8_ENABLE_WEBASSEMBLY
259
261 Tagged<String> function_name) {
262 auto [it, was_inserted] = js_function_names_.emplace(
264 uint64_t iid = it->second;
265 if (!was_inserted) {
266 return iid;
267 }
268
269 auto* v8_function_name = serialized_interned_data_->add_v8_js_function_name();
270 v8_function_name->set_iid(iid);
271 it->first.WriteToProto(*v8_function_name);
272 return iid;
273}
274
275// static
277 perfetto::DataSourceDescriptor desc;
278 desc.set_name("dev.v8.code");
279 Base::Register(desc);
280}
281
282void CodeDataSource::OnSetup(const SetupArgs& args) {
283 config_.ParseFromString(args.config->v8_config_raw());
284}
285
289
293
294} // namespace internal
295} // namespace v8
Builtins::Kind kind
Definition builtins.cc:40
static int GetCurrentProcessId()
void Init(const CodeDataSource::TraceContext &context)
uint64_t InternJsFunctionName(Tagged< String > function_name)
uint64_t InternJsScript(Isolate &isolate, Tagged< Script > script)
void FlushInternedData(CodeDataSource::TraceContext::TracePacketHandle &packet)
std::unordered_map< ScriptUniqueId, uint64_t, ScriptUniqueId::Hash > scripts_
std::unordered_map< Function, uint64_t, Function::Hash > functions_
uint64_t InternJsFunction(Isolate &isolate, DirectHandle< SharedFunctionInfo > info, uint64_t v8_js_script_iid, int line_num, int column_num)
std::unordered_map< int, uint64_t > isolates_
protozero::HeapBuffered< perfetto::protos::pbzero::InternedData > serialized_interned_data_
std::unordered_map< PerfettoV8String, uint64_t, PerfettoV8String::Hasher > js_function_names_
perfetto::protos::gen::V8Config config_
void OnSetup(const SetupArgs &) override
void OnStart(const StartArgs &) override
void OnStop(const StopArgs &) override
static IsolateGroup * current()
void WriteToProto(Proto &proto) const
static Handle< String > DebugName(Isolate *isolate, DirectHandle< SharedFunctionInfo > shared)
base::Vector< const uint8_t > wire_bytes() const
PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(v8::internal::CodeDataSource, v8::internal::CodeDataSourceTraits)
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
Tagged(T object) -> Tagged< T >
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150