v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
builtins-trace.cc
Go to the documentation of this file.
1// Copyright 2018 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/api/api-inl.h"
8#include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
13
14#if defined(V8_USE_PERFETTO)
15#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
16#endif
17
18namespace v8 {
19namespace internal {
20
21namespace {
22
23#define MAX_STACK_LENGTH 100
24
25class MaybeUtf8 {
26 public:
27 explicit MaybeUtf8(Isolate* isolate, DirectHandle<String> string)
28 : buf_(data_) {
29 // String::Utf8Length will also flatten the string if necessary.
30 size_t len = String::Utf8Length(isolate, string) + 1;
31 AllocateSufficientSpace(len);
32 size_t written_length =
33 String::WriteUtf8(isolate, string, reinterpret_cast<char*>(buf_), len,
35 CHECK_EQ(written_length, len);
36 }
37 const char* operator*() const { return reinterpret_cast<const char*>(buf_); }
38
39 private:
40 void AllocateSufficientSpace(size_t len) {
41 if (len + 1 > MAX_STACK_LENGTH) {
42 allocated_ = std::make_unique<uint8_t[]>(len + 1);
43 buf_ = allocated_.get();
44 }
45 }
46
47 // In the most common cases, the buffer here will be stack allocated.
48 // A heap allocation will only occur if the data is more than MAX_STACK_LENGTH
49 // Given that this is used primarily for trace event categories and names,
50 // the MAX_STACK_LENGTH should be more than enough.
51 uint8_t* buf_;
53 std::unique_ptr<uint8_t[]> allocated_;
54};
55
56#if !defined(V8_USE_PERFETTO)
57class JsonTraceValue : public ConvertableToTraceFormat {
58 public:
59 explicit JsonTraceValue(Isolate* isolate, DirectHandle<String> object) {
60 // object is a JSON string serialized using JSON.stringify() from within
61 // the BUILTIN(Trace) method. This may (likely) contain UTF8 values so
62 // to grab the appropriate buffer data we have to serialize it out. We
63 // hold on to the bits until the AppendAsTraceFormat method is called.
64 MaybeUtf8 data(isolate, object);
65 data_ = *data;
66 }
67
68 void AppendAsTraceFormat(std::string* out) const override { *out += data_; }
69
70 private:
71 std::string data_;
72};
73
74const uint8_t* GetCategoryGroupEnabled(Isolate* isolate,
75 DirectHandle<String> string) {
76 MaybeUtf8 category(isolate, string);
78}
79#endif // !defined(V8_USE_PERFETTO)
80
81#undef MAX_STACK_LENGTH
82
83} // namespace
84
85// Builins::kIsTraceCategoryEnabled(category) : bool
86BUILTIN(IsTraceCategoryEnabled) {
87 HandleScope scope(isolate);
88 DirectHandle<Object> category = args.atOrUndefined(isolate, 1);
89 if (v8_flags.fuzzing) {
90 // Category handling has many CHECKs we don't want to hit.
91 return ReadOnlyRoots(isolate).false_value();
92 }
93 if (!IsString(*category)) {
95 isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
96 }
97 bool enabled;
98#if defined(V8_USE_PERFETTO)
99 MaybeUtf8 category_str(isolate, Cast<String>(category));
100 perfetto::DynamicCategory dynamic_category{*category_str};
101 enabled = TRACE_EVENT_CATEGORY_ENABLED(dynamic_category);
102#else
103 enabled = *GetCategoryGroupEnabled(isolate, Cast<String>(category));
104#endif
105 return isolate->heap()->ToBoolean(enabled);
106}
107
108// Builtin::kTrace(phase, category, name, id, data) : bool
110 HandleScope handle_scope(isolate);
111
112 DirectHandle<Object> phase_arg = args.atOrUndefined(isolate, 1);
113 DirectHandle<Object> category = args.atOrUndefined(isolate, 2);
114 DirectHandle<Object> name_arg = args.atOrUndefined(isolate, 3);
115 DirectHandle<Object> id_arg = args.atOrUndefined(isolate, 4);
116 Handle<JSAny> data_arg = Cast<JSAny>(args.atOrUndefined(isolate, 5));
117
118 if (v8_flags.fuzzing) {
119 // Category handling has many CHECKs we don't want to hit.
120 return ReadOnlyRoots(isolate).false_value();
121 }
122
123 if (!IsString(*category)) {
125 isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
126 }
127 // Exit early if the category group is not enabled.
128#if defined(V8_USE_PERFETTO)
129 MaybeUtf8 category_str(isolate, Cast<String>(category));
130 perfetto::DynamicCategory dynamic_category{*category_str};
131 if (!TRACE_EVENT_CATEGORY_ENABLED(dynamic_category))
132 return ReadOnlyRoots(isolate).false_value();
133#else
134 const uint8_t* category_group_enabled =
135 GetCategoryGroupEnabled(isolate, Cast<String>(category));
136 if (!*category_group_enabled) return ReadOnlyRoots(isolate).false_value();
137#endif
138
139 if (!IsNumber(*phase_arg)) {
141 isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError));
142 }
143 char phase = static_cast<char>(
145 if (!IsString(*name_arg)) {
147 isolate, NewTypeError(MessageTemplate::kTraceEventNameError));
148 }
149
150 uint32_t flags = TRACE_EVENT_FLAG_COPY;
151 int32_t id = 0;
152 if (!IsNullOrUndefined(*id_arg, isolate)) {
153 if (!IsNumber(*id_arg)) {
155 isolate, NewTypeError(MessageTemplate::kTraceEventIDError));
156 }
159 }
160
161 DirectHandle<String> name_str = Cast<String>(name_arg);
162 if (name_str->length() == 0) {
164 isolate, NewTypeError(MessageTemplate::kTraceEventNameLengthError));
165 }
166 MaybeUtf8 name(isolate, name_str);
167
168 // We support passing one additional trace event argument with the
169 // name "data". Any JSON serializable value may be passed.
170 static const char* arg_name = "data";
171 DirectHandle<Object> arg_json;
172 int32_t num_args = 0;
173 if (!IsUndefined(*data_arg, isolate)) {
174 // Serializes the data argument as a JSON string, which is then
175 // copied into an object. This eliminates duplicated code but
176 // could have perf costs. It is also subject to all the same
177 // limitations as JSON.stringify() as it relates to circular
178 // references and value limitations (e.g. BigInt is not supported).
180 isolate, arg_json,
181 JsonStringify(isolate, data_arg, isolate->factory()->undefined_value(),
182 isolate->factory()->undefined_value()));
183 num_args++;
184 }
185
186#if defined(V8_USE_PERFETTO)
187 // TODO(skyostil): Use interned names to reduce trace size.
188 auto trace_args = [&](perfetto::EventContext ctx) {
189 if (num_args) {
190 MaybeUtf8 arg_contents(isolate, Cast<String>(arg_json));
191 auto annotation = ctx.event()->add_debug_annotations();
192 annotation->set_name(arg_name);
193 annotation->set_legacy_json_value(*arg_contents);
194 }
195 if (flags & TRACE_EVENT_FLAG_HAS_ID) {
196 auto legacy_event = ctx.event()->set_legacy_event();
197 legacy_event->set_global_id(id);
198 }
199 };
200
201 switch (phase) {
203 TRACE_EVENT_BEGIN(dynamic_category, perfetto::DynamicString(*name),
204 trace_args);
205 break;
207 TRACE_EVENT_END(dynamic_category, trace_args);
208 break;
210 TRACE_EVENT_INSTANT(dynamic_category, perfetto::DynamicString(*name),
211 trace_args);
212 break;
213 default:
215 isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError));
216 }
217
218#else // !defined(V8_USE_PERFETTO)
219 uint8_t arg_type;
220 uint64_t arg_value;
221 if (num_args) {
222 std::unique_ptr<JsonTraceValue> traced_value(
223 new JsonTraceValue(isolate, Cast<String>(arg_json)));
224 tracing::SetTraceValue(std::move(traced_value), &arg_type, &arg_value);
225 }
226
228 phase, category_group_enabled, *name, tracing::kGlobalScope, id,
229 tracing::kNoId, num_args, &arg_name, &arg_type, &arg_value, flags);
230#endif // !defined(V8_USE_PERFETTO)
231
232 return ReadOnlyRoots(isolate).true_value();
233}
234
235} // namespace internal
236} // namespace v8
std::unique_ptr< uint8_t[]> allocated_
uint8_t * buf_
#define MAX_STACK_LENGTH
uint8_t data_[MAX_STACK_LENGTH]
#define BUILTIN(name)
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
static double NumberValue(Tagged< Number > obj)
static size_t WriteUtf8(Isolate *isolate, DirectHandle< String > string, char *buffer, size_t capacity, Utf8EncodingFlags flags, size_t *processed_characters_return=nullptr)
Definition string.cc:1113
static size_t Utf8Length(Isolate *isolate, DirectHandle< String > string)
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:284
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
Definition isolate.h:294
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
const decltype(nullptr) kGlobalScope
static V8_INLINE void SetTraceValue(T arg, unsigned char *type, uint64_t *value)
const uint64_t kNoId
bool IsNumber(Tagged< Object > obj)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
bool IsNullOrUndefined(Tagged< Object > obj, Isolate *isolate)
int32_t DoubleToInt32(double x)
V8_EXPORT_PRIVATE FlagValues v8_flags
MaybeDirectHandle< Object > JsonStringify(Isolate *isolate, Handle< JSAny > object, Handle< JSAny > replacer, Handle< Object > gap)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define CHECK_EQ(lhs, rhs)
Symbol annotation
#define TRACE_EVENT_PHASE_END
#define TRACE_EVENT_PHASE_BEGIN
#define TRACE_EVENT_PHASE_INSTANT
#define TRACE_EVENT_FLAG_HAS_ID
#define TRACE_EVENT_FLAG_COPY
#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED
Definition trace-event.h:80
#define TRACE_EVENT_API_ADD_TRACE_EVENT