diff options
author | Michaël Zasso <targos@protonmail.com> | 2018-07-25 20:03:35 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2018-09-07 21:06:51 +0200 |
commit | 5bb985d3312191d67490f9d826fd13cdbda610e9 (patch) | |
tree | da8457d9ab381ebd5e5907dda5dcd78515e0748d /deps/v8/src | |
parent | f04ab3c756485762a42ed5db76bc417418c9caf4 (diff) | |
download | android-node-v8-5bb985d3312191d67490f9d826fd13cdbda610e9.tar.gz android-node-v8-5bb985d3312191d67490f9d826fd13cdbda610e9.tar.bz2 android-node-v8-5bb985d3312191d67490f9d826fd13cdbda610e9.zip |
deps: cherry-pick 0dd3390 from upstream V8
Original commit message:
Reland "[builtins] Add %IsTraceCategoryEnabled and %Trace builtins"
This is a reland of 8d4572a22b5d2fa0547195bcc40baa18b7565386
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: https://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: https://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}
Refs: https://github.com/v8/v8/commit/0dd33901a16c7c64290b7e7ddf13945b773c5d79
PR-URL: https://github.com/nodejs/node/pull/21983
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'deps/v8/src')
-rw-r--r-- | deps/v8/src/bootstrapper.cc | 9 | ||||
-rw-r--r-- | deps/v8/src/builtins/builtins-definitions.h | 6 | ||||
-rw-r--r-- | deps/v8/src/builtins/builtins-trace.cc | 191 | ||||
-rw-r--r-- | deps/v8/src/debug/debug-evaluate.cc | 3 | ||||
-rw-r--r-- | deps/v8/src/messages.h | 9 |
5 files changed, 216 insertions, 2 deletions
diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 6723f3d5d4..656650cd64 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -5077,6 +5077,15 @@ bool Genesis::InstallExtraNatives() { Handle<JSObject> extras_binding = factory()->NewJSObject(isolate()->object_function()); + + // binding.isTraceCategoryEnabled(category) + SimpleInstallFunction(isolate(), extras_binding, "isTraceCategoryEnabled", + Builtins::kIsTraceCategoryEnabled, 1, true); + + // binding.trace(phase, category, name, id, data) + SimpleInstallFunction(isolate(), extras_binding, "trace", Builtins::kTrace, 5, + true); + native_context()->set_extras_binding_object(*extras_binding); for (int i = ExtraNatives::GetDebuggerCount(); diff --git a/deps/v8/src/builtins/builtins-definitions.h b/deps/v8/src/builtins/builtins-definitions.h index 46b02d88d8..2d7c780c70 100644 --- a/deps/v8/src/builtins/builtins-definitions.h +++ b/deps/v8/src/builtins/builtins-definitions.h @@ -1308,7 +1308,11 @@ namespace internal { ASM(CallApiGetter) \ 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) \ diff --git a/deps/v8/src/builtins/builtins-trace.cc b/deps/v8/src/builtins/builtins-trace.cc new file mode 100644 index 0000000000..cd0f5a77d0 --- /dev/null +++ b/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(isolate, 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 ReadOnlyRoots(isolate).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 ReadOnlyRoots(isolate).true_value(); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/debug/debug-evaluate.cc b/deps/v8/src/debug/debug-evaluate.cc index 0dd2303772..d263fa45a9 100644 --- a/deps/v8/src/debug/debug-evaluate.cc +++ b/deps/v8/src/debug/debug-evaluate.cc @@ -567,6 +567,9 @@ DebugInfo::SideEffectState BuiltinGetSideEffectState(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: diff --git a/deps/v8/src/messages.h b/deps/v8/src/messages.h index 1d1a07d7b6..68078bb373 100644 --- a/deps/v8/src/messages.h +++ b/deps/v8/src/messages.h @@ -757,7 +757,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: |