deps: V8: Backport of 0dd3390 from upstream
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} PR-URL: https://github.com/nodejs/node/pull/21899 Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
This commit is contained in:
parent
de8a8d056c
commit
a706456f71
@ -28,7 +28,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.17',
|
||||
'v8_embedder_string': '-node.18',
|
||||
|
||||
# Enable disassembler for `--print-code` v8 options
|
||||
'v8_enable_disassembler': 1,
|
||||
|
1
deps/v8/AUTHORS
vendored
1
deps/v8/AUTHORS
vendored
@ -82,6 +82,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>
|
||||
|
1
deps/v8/BUILD.gn
vendored
1
deps/v8/BUILD.gn
vendored
@ -1420,6 +1420,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-typedarray.cc",
|
||||
"src/builtins/builtins-utils.h",
|
||||
"src/builtins/builtins.cc",
|
||||
|
1
deps/v8/gypfiles/v8.gyp
vendored
1
deps/v8/gypfiles/v8.gyp
vendored
@ -626,6 +626,7 @@
|
||||
'../src/builtins/builtins-intl.cc',
|
||||
'../src/builtins/builtins-intl.h',
|
||||
'../src/builtins/builtins-symbol.cc',
|
||||
'../src/builtins/builtins-trace.cc',
|
||||
'../src/builtins/builtins-typedarray.cc',
|
||||
'../src/builtins/builtins-utils.h',
|
||||
'../src/builtins/builtins.cc',
|
||||
|
9
deps/v8/src/bootstrapper.cc
vendored
9
deps/v8/src/bootstrapper.cc
vendored
@ -4947,6 +4947,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();
|
||||
|
6
deps/v8/src/builtins/builtins-definitions.h
vendored
6
deps/v8/src/builtins/builtins-definitions.h
vendored
@ -1247,7 +1247,11 @@ namespace internal {
|
||||
/* #sec-%asyncfromsynciteratorprototype%.return */ \
|
||||
TFJ(AsyncFromSyncIteratorPrototypeReturn, 1, kValue) \
|
||||
/* #sec-async-iterator-value-unwrap-functions */ \
|
||||
TFJ(AsyncIteratorValueUnwrap, 1, kValue)
|
||||
TFJ(AsyncIteratorValueUnwrap, 1, kValue) \
|
||||
\
|
||||
/* Trace */ \
|
||||
CPP(IsTraceCategoryEnabled) \
|
||||
CPP(Trace)
|
||||
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
#define BUILTIN_LIST(CPP, API, TFJ, TFC, TFS, TFH, ASM) \
|
||||
|
191
deps/v8/src/builtins/builtins-trace.cc
vendored
Normal file
191
deps/v8/src/builtins/builtins-trace.cc
vendored
Normal file
@ -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
deps/v8/src/debug/debug-evaluate.cc
vendored
3
deps/v8/src/debug/debug-evaluate.cc
vendored
@ -621,6 +621,9 @@ bool BuiltinHasNoSideEffect(Builtins::Name id) {
|
||||
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:
|
||||
|
9
deps/v8/src/messages.h
vendored
9
deps/v8/src/messages.h
vendored
@ -755,7 +755,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:
|
||||
|
134
deps/v8/test/cctest/test-trace-event.cc
vendored
134
deps/v8/test/cctest/test-trace-event.cc
vendored
@ -75,7 +75,7 @@ class MockTracingController : public v8::TracingController {
|
||||
const char* name, uint64_t handle) override {}
|
||||
|
||||
const uint8_t* GetCategoryGroupEnabled(const char* name) override {
|
||||
if (strcmp(name, "v8-cat")) {
|
||||
if (strncmp(name, "v8-cat", 6)) {
|
||||
static uint8_t no = 0;
|
||||
return &no;
|
||||
} else {
|
||||
@ -274,3 +274,135 @@ TEST(TestEventWithTimestamp) {
|
||||
CHECK_EQ(13832, GET_TRACE_OBJECT(2)->timestamp);
|
||||
CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args);
|
||||
}
|
||||
|
||||
TEST(BuiltinsIsTraceCategoryEnabled) {
|
||||
CcTest::InitializeVM();
|
||||
MockTracingPlatform platform;
|
||||
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
LocalContext env;
|
||||
|
||||
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
|
||||
CHECK(!binding.IsEmpty());
|
||||
|
||||
auto undefined = v8::Undefined(isolate);
|
||||
auto isTraceCategoryEnabled =
|
||||
binding->Get(env.local(), v8_str("isTraceCategoryEnabled"))
|
||||
.ToLocalChecked()
|
||||
.As<v8::Function>();
|
||||
|
||||
{
|
||||
// Test with an enabled category
|
||||
v8::Local<v8::Value> argv[] = {v8_str("v8-cat")};
|
||||
auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
|
||||
.ToLocalChecked()
|
||||
.As<v8::Boolean>();
|
||||
|
||||
CHECK(result->BooleanValue());
|
||||
}
|
||||
|
||||
{
|
||||
// Test with a disabled category
|
||||
v8::Local<v8::Value> argv[] = {v8_str("cat")};
|
||||
auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
|
||||
.ToLocalChecked()
|
||||
.As<v8::Boolean>();
|
||||
|
||||
CHECK(!result->BooleanValue());
|
||||
}
|
||||
|
||||
{
|
||||
// Test with an enabled utf8 category
|
||||
v8::Local<v8::Value> argv[] = {v8_str("v8-cat\u20ac")};
|
||||
auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
|
||||
.ToLocalChecked()
|
||||
.As<v8::Boolean>();
|
||||
|
||||
CHECK(result->BooleanValue());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BuiltinsTrace) {
|
||||
CcTest::InitializeVM();
|
||||
MockTracingPlatform platform;
|
||||
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
LocalContext env;
|
||||
|
||||
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
|
||||
CHECK(!binding.IsEmpty());
|
||||
|
||||
auto undefined = v8::Undefined(isolate);
|
||||
auto trace = binding->Get(env.local(), v8_str("trace"))
|
||||
.ToLocalChecked()
|
||||
.As<v8::Function>();
|
||||
|
||||
// Test with disabled category
|
||||
{
|
||||
v8::Local<v8::String> category = v8_str("cat");
|
||||
v8::Local<v8::String> name = v8_str("name");
|
||||
v8::Local<v8::Value> argv[] = {
|
||||
v8::Integer::New(isolate, 'b'), // phase
|
||||
category, name, v8::Integer::New(isolate, 0), // id
|
||||
undefined // data
|
||||
};
|
||||
auto result = trace->Call(env.local(), undefined, 5, argv)
|
||||
.ToLocalChecked()
|
||||
.As<v8::Boolean>();
|
||||
|
||||
CHECK(!result->BooleanValue());
|
||||
CHECK_EQ(0, GET_TRACE_OBJECTS_LIST->size());
|
||||
}
|
||||
|
||||
// Test with enabled category
|
||||
{
|
||||
v8::Local<v8::String> category = v8_str("v8-cat");
|
||||
v8::Local<v8::String> name = v8_str("name");
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::Object> data = v8::Object::New(isolate);
|
||||
data->Set(context, v8_str("foo"), v8_str("bar")).FromJust();
|
||||
v8::Local<v8::Value> argv[] = {
|
||||
v8::Integer::New(isolate, 'b'), // phase
|
||||
category, name, v8::Integer::New(isolate, 123), // id
|
||||
data // data arg
|
||||
};
|
||||
auto result = trace->Call(env.local(), undefined, 5, argv)
|
||||
.ToLocalChecked()
|
||||
.As<v8::Boolean>();
|
||||
|
||||
CHECK(result->BooleanValue());
|
||||
CHECK_EQ(1, GET_TRACE_OBJECTS_LIST->size());
|
||||
|
||||
CHECK_EQ(123, GET_TRACE_OBJECT(0)->id);
|
||||
CHECK_EQ('b', GET_TRACE_OBJECT(0)->phase);
|
||||
CHECK_EQ("name", GET_TRACE_OBJECT(0)->name);
|
||||
CHECK_EQ(1, GET_TRACE_OBJECT(0)->num_args);
|
||||
}
|
||||
|
||||
// Test with enabled utf8 category
|
||||
{
|
||||
v8::Local<v8::String> category = v8_str("v8-cat\u20ac");
|
||||
v8::Local<v8::String> name = v8_str("name\u20ac");
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::Object> data = v8::Object::New(isolate);
|
||||
data->Set(context, v8_str("foo"), v8_str("bar")).FromJust();
|
||||
v8::Local<v8::Value> argv[] = {
|
||||
v8::Integer::New(isolate, 'b'), // phase
|
||||
category, name, v8::Integer::New(isolate, 123), // id
|
||||
data // data arg
|
||||
};
|
||||
auto result = trace->Call(env.local(), undefined, 5, argv)
|
||||
.ToLocalChecked()
|
||||
.As<v8::Boolean>();
|
||||
|
||||
CHECK(result->BooleanValue());
|
||||
CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->size());
|
||||
|
||||
CHECK_EQ(123, GET_TRACE_OBJECT(1)->id);
|
||||
CHECK_EQ('b', GET_TRACE_OBJECT(1)->phase);
|
||||
CHECK_EQ("name\u20ac", GET_TRACE_OBJECT(1)->name);
|
||||
CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user