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