V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
builtins-trace.cc
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-inl.h"
6 #include "src/builtins/builtins-utils-inl.h"
7 #include "src/builtins/builtins.h"
8 #include "src/counters.h"
9 #include "src/json-stringifier.h"
10 #include "src/objects-inl.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 namespace {
16 
18 
19 #define MAX_STACK_LENGTH 100
20 
21 class MaybeUtf8 {
22  public:
23  explicit MaybeUtf8(Isolate* isolate, Handle<String> string) : buf_(data_) {
24  string = String::Flatten(isolate, string);
25  int len;
26  if (string->IsOneByteRepresentation()) {
27  // Technically this allows unescaped latin1 characters but the trace
28  // events mechanism currently does the same and the current consuming
29  // tools are tolerant of it. A more correct approach here would be to
30  // escape non-ascii characters but this is easier and faster.
31  len = string->length();
32  AllocateSufficientSpace(len);
33  if (len > 0) {
34  // Why copy? Well, the trace event mechanism requires null-terminated
35  // strings, the bytes we get from SeqOneByteString are not. buf_ is
36  // guaranteed to be null terminated.
37  DisallowHeapAllocation no_gc;
38  memcpy(buf_, Handle<SeqOneByteString>::cast(string)->GetChars(), len);
39  }
40  } else {
41  Local<v8::String> local = Utils::ToLocal(string);
42  auto* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
43  len = local->Utf8Length(v8_isolate);
44  AllocateSufficientSpace(len);
45  if (len > 0) {
46  local->WriteUtf8(v8_isolate, reinterpret_cast<char*>(buf_));
47  }
48  }
49  buf_[len] = 0;
50  }
51  const char* operator*() const { return reinterpret_cast<const char*>(buf_); }
52 
53  private:
54  void AllocateSufficientSpace(int len) {
55  if (len + 1 > MAX_STACK_LENGTH) {
56  allocated_.reset(new uint8_t[len + 1]);
57  buf_ = allocated_.get();
58  }
59  }
60 
61  // In the most common cases, the buffer here will be stack allocated.
62  // A heap allocation will only occur if the data is more than MAX_STACK_LENGTH
63  // Given that this is used primarily for trace event categories and names,
64  // the MAX_STACK_LENGTH should be more than enough.
65  uint8_t* buf_;
66  uint8_t data_[MAX_STACK_LENGTH];
67  std::unique_ptr<uint8_t> allocated_;
68 };
69 
70 class JsonTraceValue : public ConvertableToTraceFormat {
71  public:
72  explicit JsonTraceValue(Isolate* isolate, Handle<String> object) {
73  // object is a JSON string serialized using JSON.stringify() from within
74  // the BUILTIN(Trace) method. This may (likely) contain UTF8 values so
75  // to grab the appropriate buffer data we have to serialize it out. We
76  // hold on to the bits until the AppendAsTraceFormat method is called.
77  MaybeUtf8 data(isolate, object);
78  data_ = *data;
79  }
80 
81  void AppendAsTraceFormat(std::string* out) const override { *out += data_; }
82 
83  private:
84  std::string data_;
85 };
86 
87 const uint8_t* GetCategoryGroupEnabled(Isolate* isolate,
88  Handle<String> string) {
89  MaybeUtf8 category(isolate, string);
90  return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(*category);
91 }
92 
93 #undef MAX_STACK_LENGTH
94 
95 } // namespace
96 
97 // Builins::kIsTraceCategoryEnabled(category) : bool
98 BUILTIN(IsTraceCategoryEnabled) {
99  HandleScope scope(isolate);
100  Handle<Object> category = args.atOrUndefined(isolate, 1);
101  if (!category->IsString()) {
102  THROW_NEW_ERROR_RETURN_FAILURE(
103  isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
104  }
105  return isolate->heap()->ToBoolean(
106  *GetCategoryGroupEnabled(isolate, Handle<String>::cast(category)));
107 }
108 
109 // Builtins::kTrace(phase, category, name, id, data) : bool
110 BUILTIN(Trace) {
111  HandleScope handle_scope(isolate);
112 
113  Handle<Object> phase_arg = args.atOrUndefined(isolate, 1);
114  Handle<Object> category = args.atOrUndefined(isolate, 2);
115  Handle<Object> name_arg = args.atOrUndefined(isolate, 3);
116  Handle<Object> id_arg = args.atOrUndefined(isolate, 4);
117  Handle<Object> data_arg = args.atOrUndefined(isolate, 5);
118 
119  const uint8_t* category_group_enabled =
120  GetCategoryGroupEnabled(isolate, Handle<String>::cast(category));
121 
122  // Exit early if the category group is not enabled.
123  if (!*category_group_enabled) {
124  return ReadOnlyRoots(isolate).false_value();
125  }
126 
127  if (!phase_arg->IsNumber()) {
128  THROW_NEW_ERROR_RETURN_FAILURE(
129  isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError));
130  }
131  if (!category->IsString()) {
132  THROW_NEW_ERROR_RETURN_FAILURE(
133  isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
134  }
135  if (!name_arg->IsString()) {
136  THROW_NEW_ERROR_RETURN_FAILURE(
137  isolate, NewTypeError(MessageTemplate::kTraceEventNameError));
138  }
139 
140  uint32_t flags = TRACE_EVENT_FLAG_COPY;
141  int32_t id = 0;
142  if (!id_arg->IsNullOrUndefined(isolate)) {
143  if (!id_arg->IsNumber()) {
144  THROW_NEW_ERROR_RETURN_FAILURE(
145  isolate, NewTypeError(MessageTemplate::kTraceEventIDError));
146  }
147  flags |= TRACE_EVENT_FLAG_HAS_ID;
148  id = DoubleToInt32(id_arg->Number());
149  }
150 
151  Handle<String> name_str = Handle<String>::cast(name_arg);
152  if (name_str->length() == 0) {
153  THROW_NEW_ERROR_RETURN_FAILURE(
154  isolate, NewTypeError(MessageTemplate::kTraceEventNameLengthError));
155  }
156  MaybeUtf8 name(isolate, name_str);
157 
158  // We support passing one additional trace event argument with the
159  // name "data". Any JSON serializable value may be passed.
160  static const char* arg_name = "data";
161  int32_t num_args = 0;
162  uint8_t arg_type;
163  uint64_t arg_value;
164 
165  if (!data_arg->IsUndefined(isolate)) {
166  // Serializes the data argument as a JSON string, which is then
167  // copied into an object. This eliminates duplicated code but
168  // could have perf costs. It is also subject to all the same
169  // limitations as JSON.stringify() as it relates to circular
170  // references and value limitations (e.g. BigInt is not supported).
171  Handle<Object> result;
172  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
173  isolate, result,
174  JsonStringify(isolate, data_arg, isolate->factory()->undefined_value(),
175  isolate->factory()->undefined_value()));
176  std::unique_ptr<JsonTraceValue> traced_value;
177  traced_value.reset(
178  new JsonTraceValue(isolate, Handle<String>::cast(result)));
179  tracing::SetTraceValue(std::move(traced_value), &arg_type, &arg_value);
180  num_args++;
181  }
182 
183  TRACE_EVENT_API_ADD_TRACE_EVENT(
184  static_cast<char>(DoubleToInt32(phase_arg->Number())),
185  category_group_enabled, *name, tracing::kGlobalScope, id, tracing::kNoId,
186  num_args, &arg_name, &arg_type, &arg_value, flags);
187 
188  return ReadOnlyRoots(isolate).true_value();
189 }
190 
191 } // namespace internal
192 } // namespace v8
Definition: libplatform.h:13