11cb0ef41Sopenharmony_ci// Copyright 2018 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/api/api-inl.h"
61cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils-inl.h"
71cb0ef41Sopenharmony_ci#include "src/builtins/builtins.h"
81cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h"  // For ToBoolean. TODO(jkummerow): Drop.
91cb0ef41Sopenharmony_ci#include "src/json/json-stringifier.h"
101cb0ef41Sopenharmony_ci#include "src/logging/counters.h"
111cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
121cb0ef41Sopenharmony_ci#include "src/tracing/traced-value.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci#if defined(V8_USE_PERFETTO)
151cb0ef41Sopenharmony_ci#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
161cb0ef41Sopenharmony_ci#include "src/base/platform/wrappers.h"
171cb0ef41Sopenharmony_ci#endif
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_cinamespace v8 {
201cb0ef41Sopenharmony_cinamespace internal {
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_cinamespace {
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciusing v8::tracing::TracedValue;
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci#define MAX_STACK_LENGTH 100
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ciclass MaybeUtf8 {
291cb0ef41Sopenharmony_ci public:
301cb0ef41Sopenharmony_ci  explicit MaybeUtf8(Isolate* isolate, Handle<String> string) : buf_(data_) {
311cb0ef41Sopenharmony_ci    string = String::Flatten(isolate, string);
321cb0ef41Sopenharmony_ci    int len;
331cb0ef41Sopenharmony_ci    if (string->IsOneByteRepresentation()) {
341cb0ef41Sopenharmony_ci      // Technically this allows unescaped latin1 characters but the trace
351cb0ef41Sopenharmony_ci      // events mechanism currently does the same and the current consuming
361cb0ef41Sopenharmony_ci      // tools are tolerant of it. A more correct approach here would be to
371cb0ef41Sopenharmony_ci      // escape non-ascii characters but this is easier and faster.
381cb0ef41Sopenharmony_ci      len = string->length();
391cb0ef41Sopenharmony_ci      AllocateSufficientSpace(len);
401cb0ef41Sopenharmony_ci      if (len > 0) {
411cb0ef41Sopenharmony_ci        // Why copy? Well, the trace event mechanism requires null-terminated
421cb0ef41Sopenharmony_ci        // strings, the bytes we get from SeqOneByteString are not. buf_ is
431cb0ef41Sopenharmony_ci        // guaranteed to be null terminated.
441cb0ef41Sopenharmony_ci        DisallowGarbageCollection no_gc;
451cb0ef41Sopenharmony_ci        memcpy(buf_, Handle<SeqOneByteString>::cast(string)->GetChars(no_gc),
461cb0ef41Sopenharmony_ci               len);
471cb0ef41Sopenharmony_ci      }
481cb0ef41Sopenharmony_ci    } else {
491cb0ef41Sopenharmony_ci      Local<v8::String> local = Utils::ToLocal(string);
501cb0ef41Sopenharmony_ci      auto* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
511cb0ef41Sopenharmony_ci      len = local->Utf8Length(v8_isolate);
521cb0ef41Sopenharmony_ci      AllocateSufficientSpace(len);
531cb0ef41Sopenharmony_ci      if (len > 0) {
541cb0ef41Sopenharmony_ci        local->WriteUtf8(v8_isolate, reinterpret_cast<char*>(buf_));
551cb0ef41Sopenharmony_ci      }
561cb0ef41Sopenharmony_ci    }
571cb0ef41Sopenharmony_ci    buf_[len] = 0;
581cb0ef41Sopenharmony_ci  }
591cb0ef41Sopenharmony_ci  const char* operator*() const { return reinterpret_cast<const char*>(buf_); }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci private:
621cb0ef41Sopenharmony_ci  void AllocateSufficientSpace(int len) {
631cb0ef41Sopenharmony_ci    if (len + 1 > MAX_STACK_LENGTH) {
641cb0ef41Sopenharmony_ci      allocated_ = std::make_unique<uint8_t[]>(len + 1);
651cb0ef41Sopenharmony_ci      buf_ = allocated_.get();
661cb0ef41Sopenharmony_ci    }
671cb0ef41Sopenharmony_ci  }
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  // In the most common cases, the buffer here will be stack allocated.
701cb0ef41Sopenharmony_ci  // A heap allocation will only occur if the data is more than MAX_STACK_LENGTH
711cb0ef41Sopenharmony_ci  // Given that this is used primarily for trace event categories and names,
721cb0ef41Sopenharmony_ci  // the MAX_STACK_LENGTH should be more than enough.
731cb0ef41Sopenharmony_ci  uint8_t* buf_;
741cb0ef41Sopenharmony_ci  uint8_t data_[MAX_STACK_LENGTH];
751cb0ef41Sopenharmony_ci  std::unique_ptr<uint8_t[]> allocated_;
761cb0ef41Sopenharmony_ci};
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci#if !defined(V8_USE_PERFETTO)
791cb0ef41Sopenharmony_ciclass JsonTraceValue : public ConvertableToTraceFormat {
801cb0ef41Sopenharmony_ci public:
811cb0ef41Sopenharmony_ci  explicit JsonTraceValue(Isolate* isolate, Handle<String> object) {
821cb0ef41Sopenharmony_ci    // object is a JSON string serialized using JSON.stringify() from within
831cb0ef41Sopenharmony_ci    // the BUILTIN(Trace) method. This may (likely) contain UTF8 values so
841cb0ef41Sopenharmony_ci    // to grab the appropriate buffer data we have to serialize it out. We
851cb0ef41Sopenharmony_ci    // hold on to the bits until the AppendAsTraceFormat method is called.
861cb0ef41Sopenharmony_ci    MaybeUtf8 data(isolate, object);
871cb0ef41Sopenharmony_ci    data_ = *data;
881cb0ef41Sopenharmony_ci  }
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  void AppendAsTraceFormat(std::string* out) const override { *out += data_; }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci private:
931cb0ef41Sopenharmony_ci  std::string data_;
941cb0ef41Sopenharmony_ci};
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ciconst uint8_t* GetCategoryGroupEnabled(Isolate* isolate,
971cb0ef41Sopenharmony_ci                                       Handle<String> string) {
981cb0ef41Sopenharmony_ci  MaybeUtf8 category(isolate, string);
991cb0ef41Sopenharmony_ci  return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(*category);
1001cb0ef41Sopenharmony_ci}
1011cb0ef41Sopenharmony_ci#endif  // !defined(V8_USE_PERFETTO)
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci#undef MAX_STACK_LENGTH
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci}  // namespace
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci// Builins::kIsTraceCategoryEnabled(category) : bool
1081cb0ef41Sopenharmony_ciBUILTIN(IsTraceCategoryEnabled) {
1091cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
1101cb0ef41Sopenharmony_ci  Handle<Object> category = args.atOrUndefined(isolate, 1);
1111cb0ef41Sopenharmony_ci  if (!category->IsString()) {
1121cb0ef41Sopenharmony_ci    THROW_NEW_ERROR_RETURN_FAILURE(
1131cb0ef41Sopenharmony_ci        isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
1141cb0ef41Sopenharmony_ci  }
1151cb0ef41Sopenharmony_ci  bool enabled;
1161cb0ef41Sopenharmony_ci#if defined(V8_USE_PERFETTO)
1171cb0ef41Sopenharmony_ci  MaybeUtf8 category_str(isolate, Handle<String>::cast(category));
1181cb0ef41Sopenharmony_ci  perfetto::DynamicCategory dynamic_category{*category_str};
1191cb0ef41Sopenharmony_ci  enabled = TRACE_EVENT_CATEGORY_ENABLED(dynamic_category);
1201cb0ef41Sopenharmony_ci#else
1211cb0ef41Sopenharmony_ci  enabled = *GetCategoryGroupEnabled(isolate, Handle<String>::cast(category));
1221cb0ef41Sopenharmony_ci#endif
1231cb0ef41Sopenharmony_ci  return isolate->heap()->ToBoolean(enabled);
1241cb0ef41Sopenharmony_ci}
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci// Builtin::kTrace(phase, category, name, id, data) : bool
1271cb0ef41Sopenharmony_ciBUILTIN(Trace) {
1281cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci  Handle<Object> phase_arg = args.atOrUndefined(isolate, 1);
1311cb0ef41Sopenharmony_ci  Handle<Object> category = args.atOrUndefined(isolate, 2);
1321cb0ef41Sopenharmony_ci  Handle<Object> name_arg = args.atOrUndefined(isolate, 3);
1331cb0ef41Sopenharmony_ci  Handle<Object> id_arg = args.atOrUndefined(isolate, 4);
1341cb0ef41Sopenharmony_ci  Handle<Object> data_arg = args.atOrUndefined(isolate, 5);
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci  // Exit early if the category group is not enabled.
1371cb0ef41Sopenharmony_ci#if defined(V8_USE_PERFETTO)
1381cb0ef41Sopenharmony_ci  MaybeUtf8 category_str(isolate, Handle<String>::cast(category));
1391cb0ef41Sopenharmony_ci  perfetto::DynamicCategory dynamic_category{*category_str};
1401cb0ef41Sopenharmony_ci  if (!TRACE_EVENT_CATEGORY_ENABLED(dynamic_category))
1411cb0ef41Sopenharmony_ci    return ReadOnlyRoots(isolate).false_value();
1421cb0ef41Sopenharmony_ci#else
1431cb0ef41Sopenharmony_ci  const uint8_t* category_group_enabled =
1441cb0ef41Sopenharmony_ci      GetCategoryGroupEnabled(isolate, Handle<String>::cast(category));
1451cb0ef41Sopenharmony_ci  if (!*category_group_enabled) return ReadOnlyRoots(isolate).false_value();
1461cb0ef41Sopenharmony_ci#endif
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci  if (!phase_arg->IsNumber()) {
1491cb0ef41Sopenharmony_ci    THROW_NEW_ERROR_RETURN_FAILURE(
1501cb0ef41Sopenharmony_ci        isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError));
1511cb0ef41Sopenharmony_ci  }
1521cb0ef41Sopenharmony_ci  char phase = static_cast<char>(DoubleToInt32(phase_arg->Number()));
1531cb0ef41Sopenharmony_ci  if (!category->IsString()) {
1541cb0ef41Sopenharmony_ci    THROW_NEW_ERROR_RETURN_FAILURE(
1551cb0ef41Sopenharmony_ci        isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
1561cb0ef41Sopenharmony_ci  }
1571cb0ef41Sopenharmony_ci  if (!name_arg->IsString()) {
1581cb0ef41Sopenharmony_ci    THROW_NEW_ERROR_RETURN_FAILURE(
1591cb0ef41Sopenharmony_ci        isolate, NewTypeError(MessageTemplate::kTraceEventNameError));
1601cb0ef41Sopenharmony_ci  }
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  uint32_t flags = TRACE_EVENT_FLAG_COPY;
1631cb0ef41Sopenharmony_ci  int32_t id = 0;
1641cb0ef41Sopenharmony_ci  if (!id_arg->IsNullOrUndefined(isolate)) {
1651cb0ef41Sopenharmony_ci    if (!id_arg->IsNumber()) {
1661cb0ef41Sopenharmony_ci      THROW_NEW_ERROR_RETURN_FAILURE(
1671cb0ef41Sopenharmony_ci          isolate, NewTypeError(MessageTemplate::kTraceEventIDError));
1681cb0ef41Sopenharmony_ci    }
1691cb0ef41Sopenharmony_ci    flags |= TRACE_EVENT_FLAG_HAS_ID;
1701cb0ef41Sopenharmony_ci    id = DoubleToInt32(id_arg->Number());
1711cb0ef41Sopenharmony_ci  }
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci  Handle<String> name_str = Handle<String>::cast(name_arg);
1741cb0ef41Sopenharmony_ci  if (name_str->length() == 0) {
1751cb0ef41Sopenharmony_ci    THROW_NEW_ERROR_RETURN_FAILURE(
1761cb0ef41Sopenharmony_ci        isolate, NewTypeError(MessageTemplate::kTraceEventNameLengthError));
1771cb0ef41Sopenharmony_ci  }
1781cb0ef41Sopenharmony_ci  MaybeUtf8 name(isolate, name_str);
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci  // We support passing one additional trace event argument with the
1811cb0ef41Sopenharmony_ci  // name "data". Any JSON serializable value may be passed.
1821cb0ef41Sopenharmony_ci  static const char* arg_name = "data";
1831cb0ef41Sopenharmony_ci  Handle<Object> arg_json;
1841cb0ef41Sopenharmony_ci  int32_t num_args = 0;
1851cb0ef41Sopenharmony_ci  if (!data_arg->IsUndefined(isolate)) {
1861cb0ef41Sopenharmony_ci    // Serializes the data argument as a JSON string, which is then
1871cb0ef41Sopenharmony_ci    // copied into an object. This eliminates duplicated code but
1881cb0ef41Sopenharmony_ci    // could have perf costs. It is also subject to all the same
1891cb0ef41Sopenharmony_ci    // limitations as JSON.stringify() as it relates to circular
1901cb0ef41Sopenharmony_ci    // references and value limitations (e.g. BigInt is not supported).
1911cb0ef41Sopenharmony_ci    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1921cb0ef41Sopenharmony_ci        isolate, arg_json,
1931cb0ef41Sopenharmony_ci        JsonStringify(isolate, data_arg, isolate->factory()->undefined_value(),
1941cb0ef41Sopenharmony_ci                      isolate->factory()->undefined_value()));
1951cb0ef41Sopenharmony_ci    num_args++;
1961cb0ef41Sopenharmony_ci  }
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci#if defined(V8_USE_PERFETTO)
1991cb0ef41Sopenharmony_ci  auto trace_args = [&](perfetto::EventContext ctx) {
2001cb0ef41Sopenharmony_ci    // TODO(skyostil): Use interned names to reduce trace size.
2011cb0ef41Sopenharmony_ci    if (phase != TRACE_EVENT_PHASE_END) {
2021cb0ef41Sopenharmony_ci      ctx.event()->set_name(*name);
2031cb0ef41Sopenharmony_ci    }
2041cb0ef41Sopenharmony_ci    if (num_args) {
2051cb0ef41Sopenharmony_ci      MaybeUtf8 arg_contents(isolate, Handle<String>::cast(arg_json));
2061cb0ef41Sopenharmony_ci      auto annotation = ctx.event()->add_debug_annotations();
2071cb0ef41Sopenharmony_ci      annotation->set_name(arg_name);
2081cb0ef41Sopenharmony_ci      annotation->set_legacy_json_value(*arg_contents);
2091cb0ef41Sopenharmony_ci    }
2101cb0ef41Sopenharmony_ci    if (flags & TRACE_EVENT_FLAG_HAS_ID) {
2111cb0ef41Sopenharmony_ci      auto legacy_event = ctx.event()->set_legacy_event();
2121cb0ef41Sopenharmony_ci      legacy_event->set_global_id(id);
2131cb0ef41Sopenharmony_ci    }
2141cb0ef41Sopenharmony_ci  };
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  switch (phase) {
2171cb0ef41Sopenharmony_ci    case TRACE_EVENT_PHASE_BEGIN:
2181cb0ef41Sopenharmony_ci      TRACE_EVENT_BEGIN(dynamic_category, nullptr, trace_args);
2191cb0ef41Sopenharmony_ci      break;
2201cb0ef41Sopenharmony_ci    case TRACE_EVENT_PHASE_END:
2211cb0ef41Sopenharmony_ci      TRACE_EVENT_END(dynamic_category, trace_args);
2221cb0ef41Sopenharmony_ci      break;
2231cb0ef41Sopenharmony_ci    case TRACE_EVENT_PHASE_INSTANT:
2241cb0ef41Sopenharmony_ci      TRACE_EVENT_INSTANT(dynamic_category, nullptr, trace_args);
2251cb0ef41Sopenharmony_ci      break;
2261cb0ef41Sopenharmony_ci    default:
2271cb0ef41Sopenharmony_ci      THROW_NEW_ERROR_RETURN_FAILURE(
2281cb0ef41Sopenharmony_ci          isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError));
2291cb0ef41Sopenharmony_ci  }
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci#else   // !defined(V8_USE_PERFETTO)
2321cb0ef41Sopenharmony_ci  uint8_t arg_type;
2331cb0ef41Sopenharmony_ci  uint64_t arg_value;
2341cb0ef41Sopenharmony_ci  if (num_args) {
2351cb0ef41Sopenharmony_ci    std::unique_ptr<JsonTraceValue> traced_value(
2361cb0ef41Sopenharmony_ci        new JsonTraceValue(isolate, Handle<String>::cast(arg_json)));
2371cb0ef41Sopenharmony_ci    tracing::SetTraceValue(std::move(traced_value), &arg_type, &arg_value);
2381cb0ef41Sopenharmony_ci  }
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ci  TRACE_EVENT_API_ADD_TRACE_EVENT(
2411cb0ef41Sopenharmony_ci      phase, category_group_enabled, *name, tracing::kGlobalScope, id,
2421cb0ef41Sopenharmony_ci      tracing::kNoId, num_args, &arg_name, &arg_type, &arg_value, flags);
2431cb0ef41Sopenharmony_ci#endif  // !defined(V8_USE_PERFETTO)
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci  return ReadOnlyRoots(isolate).true_value();
2461cb0ef41Sopenharmony_ci}
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci}  // namespace internal
2491cb0ef41Sopenharmony_ci}  // namespace v8
250