LCOV - code coverage report
Current view: top level - src/builtins - builtins-trace.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 47 56 83.9 %
Date: 2019-04-19 Functions: 10 14 71.4 %

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

Generated by: LCOV version 1.10