Skip to content

Commit

Permalink
deps: V8: Backport of 0dd3390 from upstream
Browse files Browse the repository at this point in the history
Original commit message:

  Reland "[builtins] Add %IsTraceCategoryEnabled and %Trace builtins"

  This is a reland of 8d4572a

  Original change's description:
  > [builtins] Add %IsTraceCategoryEnabled and %Trace builtins
  >
  > Adds the builtin Trace and IsTraceCategoryEnabled functions
  > exposed via extra bindings. These are intended to use by
  > embedders to allow basic trace event support from JavaScript.
  >
  > ```js
  > isTraceCategoryEnabled('v8.some-category')
  >
  > trace('e'.charCodeAt(0), 'v8.some-category',
  >       'Foo', 0, { abc: 'xyz'})
  > ```
  >
  > Bug: v8:7851
  > Change-Id: I7bfb9bb059efdf87d92a56a0aae326650730c250
  > Reviewed-on: chromium-review.googlesource.com/1103294
  > Commit-Queue: Yang Guo <yangguo@chromium.org>
  > Reviewed-by: Yang Guo <yangguo@chromium.org>
  > Reviewed-by: Fadi Meawad <fmeawad@chromium.org>
  > Reviewed-by: Camillo Bruni <cbruni@chromium.org>
  > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
  > Cr-Commit-Position: refs/heads/master@{#54121}

  TBR=cbruni@chromium.org

  Bug: v8:7851
  Change-Id: Id063754b2834b3b6a2b2654e76e8637bcd6aa5f8
  Reviewed-on: chromium-review.googlesource.com/1137071
  Commit-Queue: Yang Guo <yangguo@chromium.org>
  Reviewed-by: Yang Guo <yangguo@chromium.org>
  Reviewed-by: Camillo Bruni <cbruni@chromium.org>
  Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
  Cr-Commit-Position: refs/heads/master@{#54532}

Backport-PR-URL: #21668
PR-URL: #21899
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
  • Loading branch information
jasnell authored and rvagg committed Aug 15, 2018
1 parent 328c899 commit 7eccaf8
Show file tree
Hide file tree
Showing 10 changed files with 353 additions and 4 deletions.
2 changes: 1 addition & 1 deletion common.gypi
Expand Up @@ -29,7 +29,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.10',
'v8_embedder_string': '-node.11',

# Enable disassembler for `--print-code` v8 options
'v8_enable_disassembler': 1,
Expand Down
1 change: 1 addition & 0 deletions deps/v8/AUTHORS
Expand Up @@ -86,6 +86,7 @@ Jan de Mooij <jandemooij@gmail.com>
Jan Krems <jan.krems@gmail.com>
Jay Freeman <saurik@saurik.com>
James Pike <g00gle@chilon.net>
James M Snell <jasnell@gmail.com>
Jianghua Yang <jianghua.yjh@alibaba-inc.com>
Joel Stanley <joel@jms.id.au>
Johan Bergström <johan@bergstroem.nu>
Expand Down
1 change: 1 addition & 0 deletions deps/v8/BUILD.gn
Expand Up @@ -1539,6 +1539,7 @@ v8_source_set("v8_base") {
"src/builtins/builtins-sharedarraybuffer.cc",
"src/builtins/builtins-string.cc",
"src/builtins/builtins-symbol.cc",
"src/builtins/builtins-trace.cc",
"src/builtins/builtins-typed-array.cc",
"src/builtins/builtins-utils.h",
"src/builtins/builtins.cc",
Expand Down
1 change: 1 addition & 0 deletions deps/v8/gypfiles/v8.gyp
Expand Up @@ -642,6 +642,7 @@
'../src/builtins/builtins-intl.cc',
'../src/builtins/builtins-intl.h',
'../src/builtins/builtins-symbol.cc',
'../src/builtins/builtins-trace.cc',
'../src/builtins/builtins-typed-array.cc',
'../src/builtins/builtins-utils.h',
'../src/builtins/builtins.cc',
Expand Down
9 changes: 9 additions & 0 deletions deps/v8/src/bootstrapper.cc
Expand Up @@ -4981,6 +4981,15 @@ bool Genesis::InstallExtraNatives() {

Handle<JSObject> extras_binding =
factory()->NewJSObject(isolate()->object_function());

// binding.isTraceCategoryenabled(category)
SimpleInstallFunction(extras_binding, "isTraceCategoryEnabled",
Builtins::kIsTraceCategoryEnabled, 1, true);

// binding.trace(phase, category, name, id, data)
SimpleInstallFunction(extras_binding, "trace", Builtins::kTrace, 5,
true);

native_context()->set_extras_binding_object(*extras_binding);

for (int i = ExtraNatives::GetDebuggerCount();
Expand Down
6 changes: 5 additions & 1 deletion deps/v8/src/builtins/builtins-definitions.h
Expand Up @@ -1269,7 +1269,11 @@ namespace internal {
/* Miscellaneous */ \
ASM(DoubleToI) \
TFC(GetProperty, GetProperty, 1) \
ASM(MathPowInternal)
ASM(MathPowInternal) \
\
/* Trace */ \
CPP(IsTraceCategoryEnabled) \
CPP(Trace)

#ifdef V8_INTL_SUPPORT
#define BUILTIN_LIST(CPP, API, TFJ, TFC, TFS, TFH, ASM) \
Expand Down
191 changes: 191 additions & 0 deletions deps/v8/src/builtins/builtins-trace.cc
@@ -0,0 +1,191 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/api.h"
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/counters.h"
#include "src/json-stringifier.h"
#include "src/objects-inl.h"

namespace v8 {
namespace internal {

namespace {

using v8::tracing::TracedValue;

#define MAX_STACK_LENGTH 100

class MaybeUtf8 {
public:
explicit MaybeUtf8(Isolate* isolate, Handle<String> string) : buf_(data_) {
string = String::Flatten(string);
int len;
if (string->IsOneByteRepresentation()) {
// Technically this allows unescaped latin1 characters but the trace
// events mechanism currently does the same and the current consuming
// tools are tolerant of it. A more correct approach here would be to
// escape non-ascii characters but this is easier and faster.
len = string->length();
AllocateSufficientSpace(len);
if (len > 0) {
// Why copy? Well, the trace event mechanism requires null-terminated
// strings, the bytes we get from SeqOneByteString are not. buf_ is
// guaranteed to be null terminated.
memcpy(buf_, Handle<SeqOneByteString>::cast(string)->GetChars(), len);
}
} else {
Local<v8::String> local = Utils::ToLocal(string);
len = local->Utf8Length();
AllocateSufficientSpace(len);
if (len > 0) {
local->WriteUtf8(reinterpret_cast<char*>(buf_));
}
}
buf_[len] = 0;
}
const char* operator*() const { return reinterpret_cast<const char*>(buf_); }

private:
void AllocateSufficientSpace(int len) {
if (len + 1 > MAX_STACK_LENGTH) {
allocated_.reset(new uint8_t[len + 1]);
buf_ = allocated_.get();
}
}

// In the most common cases, the buffer here will be stack allocated.
// A heap allocation will only occur if the data is more than MAX_STACK_LENGTH
// Given that this is used primarily for trace event categories and names,
// the MAX_STACK_LENGTH should be more than enough.
uint8_t* buf_;
uint8_t data_[MAX_STACK_LENGTH];
std::unique_ptr<uint8_t> allocated_;
};

class JsonTraceValue : public ConvertableToTraceFormat {
public:
explicit JsonTraceValue(Isolate* isolate, Handle<String> object) {
// object is a JSON string serialized using JSON.stringify() from within
// the BUILTIN(Trace) method. This may (likely) contain UTF8 values so
// to grab the appropriate buffer data we have to serialize it out. We
// hold on to the bits until the AppendAsTraceFormat method is called.
MaybeUtf8 data(isolate, object);
data_ = *data;
}

void AppendAsTraceFormat(std::string* out) const override { *out += data_; }

private:
std::string data_;
};

const uint8_t* GetCategoryGroupEnabled(Isolate* isolate,
Handle<String> string) {
MaybeUtf8 category(isolate, string);
return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(*category);
}

#undef MAX_STACK_LENGTH

} // namespace

// Builins::kIsTraceCategoryEnabled(category) : bool
BUILTIN(IsTraceCategoryEnabled) {
HandleScope scope(isolate);
Handle<Object> category = args.atOrUndefined(isolate, 1);
if (!category->IsString()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
}
return isolate->heap()->ToBoolean(
*GetCategoryGroupEnabled(isolate, Handle<String>::cast(category)));
}

// Builtins::kTrace(phase, category, name, id, data) : bool
BUILTIN(Trace) {
HandleScope handle_scope(isolate);

Handle<Object> phase_arg = args.atOrUndefined(isolate, 1);
Handle<Object> category = args.atOrUndefined(isolate, 2);
Handle<Object> name_arg = args.atOrUndefined(isolate, 3);
Handle<Object> id_arg = args.atOrUndefined(isolate, 4);
Handle<Object> data_arg = args.atOrUndefined(isolate, 5);

const uint8_t* category_group_enabled =
GetCategoryGroupEnabled(isolate, Handle<String>::cast(category));

// Exit early if the category group is not enabled.
if (!*category_group_enabled) {
return isolate->heap()->false_value();
}

if (!phase_arg->IsNumber()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError));
}
if (!category->IsString()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
}
if (!name_arg->IsString()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventNameError));
}

uint32_t flags = TRACE_EVENT_FLAG_COPY;
int32_t id = 0;
if (!id_arg->IsNullOrUndefined(isolate)) {
if (!id_arg->IsNumber()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventIDError));
}
flags |= TRACE_EVENT_FLAG_HAS_ID;
id = DoubleToInt32(id_arg->Number());
}

Handle<String> name_str = Handle<String>::cast(name_arg);
if (name_str->length() == 0) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventNameLengthError));
}
MaybeUtf8 name(isolate, name_str);

// We support passing one additional trace event argument with the
// name "data". Any JSON serializable value may be passed.
static const char* arg_name = "data";
int32_t num_args = 0;
uint8_t arg_type;
uint64_t arg_value;

if (!data_arg->IsUndefined(isolate)) {
// Serializes the data argument as a JSON string, which is then
// copied into an object. This eliminates duplicated code but
// could have perf costs. It is also subject to all the same
// limitations as JSON.stringify() as it relates to circular
// references and value limitations (e.g. BigInt is not supported).
JsonStringifier stringifier(isolate);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
stringifier.Stringify(data_arg, isolate->factory()->undefined_value(),
isolate->factory()->undefined_value()));
std::unique_ptr<JsonTraceValue> traced_value;
traced_value.reset(
new JsonTraceValue(isolate, Handle<String>::cast(result)));
tracing::SetTraceValue(std::move(traced_value), &arg_type, &arg_value);
num_args++;
}

TRACE_EVENT_API_ADD_TRACE_EVENT(
static_cast<char>(DoubleToInt32(phase_arg->Number())),
category_group_enabled, *name, tracing::kGlobalScope, id, tracing::kNoId,
num_args, &arg_name, &arg_type, &arg_value, flags);

return isolate->heap()->true_value();
}

} // namespace internal
} // namespace v8
3 changes: 3 additions & 0 deletions deps/v8/src/debug/debug-evaluate.cc
Expand Up @@ -630,6 +630,9 @@ SharedFunctionInfo::SideEffectState BuiltinGetSideEffectState(
case Builtins::kArrayMap:
case Builtins::kArrayReduce:
case Builtins::kArrayReduceRight:
// Trace builtins
case Builtins::kIsTraceCategoryEnabled:
case Builtins::kTrace:
// TypedArray builtins.
case Builtins::kTypedArrayConstructor:
case Builtins::kTypedArrayPrototypeBuffer:
Expand Down
9 changes: 8 additions & 1 deletion deps/v8/src/messages.h
Expand Up @@ -754,7 +754,14 @@ class ErrorUtils : public AllStatic {
T(DataCloneDeserializationError, "Unable to deserialize cloned data.") \
T(DataCloneDeserializationVersionError, \
"Unable to deserialize cloned data due to invalid or unsupported " \
"version.")
"version.") \
/* Builtins-Trace Errors */ \
T(TraceEventCategoryError, "Trace event category must be a string.") \
T(TraceEventNameError, "Trace event name must be a string.") \
T(TraceEventNameLengthError, \
"Trace event name must not be an empty string.") \
T(TraceEventPhaseError, "Trace event phase must be a number.") \
T(TraceEventIDError, "Trace event id must be a number.")

class MessageTemplate {
public:
Expand Down

0 comments on commit 7eccaf8

Please sign in to comment.