LCOV - code coverage report
Current view: top level - src/builtins - builtins-trace.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 48 57 84.2 %
Date: 2019-01-20 Functions: 11 15 73.3 %

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

Generated by: LCOV version 1.10