[ VM / Service ] Add UserTag support to C-API and send UserTagChanged

events on Developer stream.

Also removes intrinsic implementations for UserTag_makeCurrent to allow
for service events to be sent on UserTag change.

TEST=DartAPI_UserTags,pkg/vm_service/test/user_tag_changed_test.dart

Change-Id: I5dc9ee77c0048590d3c6e33a652eee5bc3bf522a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/204440
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ben Konyi 2021-06-23 00:58:47 +00:00 committed by commit-bot@chromium.org
parent dc1804fff4
commit 3a4b3514bc
25 changed files with 316 additions and 114 deletions

View file

@ -159,6 +159,7 @@ String assertEventKind(String obj) {
if (obj == "ServiceUnregistered") return obj;
if (obj == "TimelineEvents") return obj;
if (obj == "TimelineStreamSubscriptionsUpdate") return obj;
if (obj == "UserTagChanged") return obj;
if (obj == "VMFlagUpdate") return obj;
if (obj == "VMUpdate") return obj;
if (obj == "WriteEvent") return obj;

View file

@ -1 +1 @@
version=3.47
version=3.48

View file

@ -26,7 +26,7 @@ export 'snapshot_graph.dart'
HeapSnapshotObjectNoData,
HeapSnapshotObjectNullData;
const String vmServiceVersion = '3.47.0';
const String vmServiceVersion = '3.48.0';
/// @optional
const String optional = 'optional';
@ -1150,6 +1150,7 @@ abstract class VmServiceInterface {
/// Debug | PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted,
/// PauseException, PausePostRequest, Resume, BreakpointAdded,
/// BreakpointResolved, BreakpointRemoved, BreakpointUpdated, Inspect, None
/// Profiler | UserTagChanged
/// GC | GC
/// Extension | Extension
/// Timeline | TimelineEvents, TimelineStreamsSubscriptionUpdate
@ -1690,6 +1691,9 @@ class VmService implements VmServiceInterface {
// PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted, PauseException, PausePostRequest, Resume, BreakpointAdded, BreakpointResolved, BreakpointRemoved, BreakpointUpdated, Inspect, None
Stream<Event> get onDebugEvent => _getEventController('Debug').stream;
// UserTagChanged
Stream<Event> get onProfilerEvent => _getEventController('Profiler').stream;
// GC
Stream<Event> get onGCEvent => _getEventController('GC').stream;
@ -2384,6 +2388,7 @@ class EventStreams {
static const String kVM = 'VM';
static const String kIsolate = 'Isolate';
static const String kDebug = 'Debug';
static const String kProfiler = 'Profiler';
static const String kGC = 'GC';
static const String kExtension = 'Extension';
static const String kTimeline = 'Timeline';
@ -2496,6 +2501,9 @@ class EventKind {
/// Notification that a Service has been removed from the Service Protocol
/// from another client.
static const String kServiceUnregistered = 'ServiceUnregistered';
/// Notification that the UserTag for an isolate has been changed.
static const String kUserTagChanged = 'UserTagChanged';
}
/// Adding new values to `InstanceKind` is considered a backwards compatible
@ -3885,6 +3893,14 @@ class Event extends Response {
@optional
bool? last;
/// The current UserTag label.
@optional
String? updatedTag;
/// The previous UserTag label.
@optional
String? previousTag;
/// Binary data associated with the event.
///
/// This is provided for the event kinds:
@ -3917,6 +3933,8 @@ class Event extends Response {
this.flag,
this.newValue,
this.last,
this.updatedTag,
this.previousTag,
this.data,
});
@ -3959,6 +3977,8 @@ class Event extends Response {
flag = json['flag'];
newValue = json['newValue'];
last = json['last'];
updatedTag = json['updatedTag'];
previousTag = json['previousTag'];
data = json['data'];
}
@ -3998,6 +4018,8 @@ class Event extends Response {
_setIfNotNull(json, 'flag', flag);
_setIfNotNull(json, 'newValue', newValue);
_setIfNotNull(json, 'last', last);
_setIfNotNull(json, 'updatedTag', updatedTag);
_setIfNotNull(json, 'previousTag', previousTag);
_setIfNotNull(json, 'data', data);
return json;
}

View file

@ -346,7 +346,7 @@ class _ServiceTesterRunner {
completer!.complete(vmIsolates.first);
completer = null;
}
return await (completer!.future as FutureOr<IsolateRef>);
return (await completer!.future) as IsolateRef;
}
}

View file

@ -0,0 +1,62 @@
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:developer';
import 'package:async/async.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
void testMain() {
final tag = UserTag('Foo');
final origTag = tag.makeCurrent();
origTag.makeCurrent();
}
late StreamQueue<Event> stream;
var tests = <IsolateTest>[
hasPausedAtStart,
(VmService service, IsolateRef isolate) async {
await service.streamListen(EventStreams.kProfiler);
stream = StreamQueue(
service.onProfilerEvent.transform(
SingleSubscriptionTransformer<Event, Event>(),
),
);
},
resumeIsolate,
hasStoppedAtExit,
(VmService service, IsolateRef isolate) async {
await service.streamCancel(EventStreams.kProfiler);
expect(await stream.hasNext, true);
var event = await stream.next;
expect(event.kind, EventKind.kUserTagChanged);
expect(event.updatedTag, 'Foo');
expect(event.previousTag, 'Default');
expect(await stream.hasNext, true);
event = await stream.next;
expect(event.kind, EventKind.kUserTagChanged);
expect(event.updatedTag, 'Default');
expect(event.previousTag, 'Foo');
},
resumeIsolate,
(VmService service, IsolateRef isolate) async {
expect(await stream.hasNext, false);
}
];
main([args = const <String>[]]) async => await runIsolateTests(
args,
tests,
'user_tag_changed_test.dart',
pause_on_start: true,
pause_on_exit: true,
testeeConcurrent: testMain,
);

View file

@ -496,4 +496,53 @@ Dart_IsolateRunnableLatencyMetric(Dart_Isolate isolate); // Microsecond
DART_EXPORT int64_t
Dart_IsolateRunnableHeapSizeMetric(Dart_Isolate isolate); // Byte
/*
* ========
* UserTags
* ========
*/
/*
* Gets the current isolate's currently set UserTag instance.
*
* \return The currently set UserTag instance.
*/
DART_EXPORT Dart_Handle Dart_GetCurrentUserTag();
/*
* Gets the current isolate's default UserTag instance.
*
* \return The default UserTag with label 'Default'
*/
DART_EXPORT Dart_Handle Dart_GetDefaultUserTag();
/*
* Creates a new UserTag instance.
*
* \param label The name of the new UserTag.
*
* \return The newly created UserTag instance or an error handle.
*/
DART_EXPORT Dart_Handle Dart_NewUserTag(const char* label);
/*
* Updates the current isolate's UserTag to a new value.
*
* \param user_tag The UserTag to be set as the current UserTag.
*
* \return The previously set UserTag instance or an error handle.
*/
DART_EXPORT Dart_Handle Dart_SetCurrentUserTag(Dart_Handle user_tag);
/*
* Returns the label of a given UserTag instance.
*
* \param user_tag The UserTag from which the label will be retrieved.
*
* \return The UserTag's label. NULL if the user_tag is invalid. The caller is
* responsible for freeing the returned label.
*/
DART_WARN_UNUSED_RESULT DART_EXPORT char* Dart_GetUserTagLabel(
Dart_Handle user_tag);
#endif // RUNTIME_INCLUDE_DART_TOOLS_API_H_

View file

@ -29,12 +29,7 @@ DEFINE_NATIVE_ENTRY(UserTag_label, 0, 1) {
DEFINE_NATIVE_ENTRY(UserTag_makeCurrent, 0, 1) {
const UserTag& self = UserTag::CheckedHandle(zone, arguments->NativeArgAt(0));
if (FLAG_trace_intrinsified_natives) {
OS::PrintErr("UserTag_makeCurrent: %s\n", self.ToCString());
}
const UserTag& old = UserTag::Handle(zone, isolate->current_tag());
self.MakeActive();
return old.ptr();
return self.MakeActive();
}
DEFINE_NATIVE_ENTRY(UserTag_defaultTag, 0, 0) {

View file

@ -12,7 +12,7 @@ var tests = <VMTest>[
final result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], 'Version');
expect(result['major'], 3);
expect(result['minor'], 47);
expect(result['minor'], 48);
expect(result['_privateMajor'], 0);
expect(result['_privateMinor'], 0);
},

View file

@ -9,10 +9,10 @@ import 'test_helper.dart';
var tests = <VMTest>[
(VM vm) async {
var result = await vm.invokeRpcNoUpgrade('getVersion', {});
final result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
expect(result['major'], equals(3));
expect(result['minor'], equals(47));
expect(result['minor'], equals(48));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},

View file

@ -2020,24 +2020,6 @@ void AsmIntrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler,
__ Branch(FieldAddress(R0, target::Function::entry_point_offset()));
}
// On stack: user tag (+0).
void AsmIntrinsifier::UserTag_makeCurrent(Assembler* assembler,
Label* normal_ir_body) {
// R1: Isolate.
__ LoadIsolate(R1);
// R0: Current user tag.
__ ldr(R0, Address(R1, target::Isolate::current_tag_offset()));
// R2: UserTag.
__ ldr(R2, Address(SP, +0 * target::kWordSize));
// Set target::Isolate::current_tag_.
__ str(R2, Address(R1, target::Isolate::current_tag_offset()));
// R2: UserTag's tag.
__ ldr(R2, FieldAddress(R2, target::UserTag::tag_offset()));
// Set target::Isolate::user_tag_.
__ str(R2, Address(R1, target::Isolate::user_tag_offset()));
__ Ret();
}
void AsmIntrinsifier::UserTag_defaultTag(Assembler* assembler,
Label* normal_ir_body) {
__ LoadIsolate(R0);

View file

@ -2224,24 +2224,6 @@ void AsmIntrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler,
__ br(R1);
}
// On stack: user tag (+0).
void AsmIntrinsifier::UserTag_makeCurrent(Assembler* assembler,
Label* normal_ir_body) {
// R1: Isolate.
__ LoadIsolate(R1);
// R0: Current user tag.
__ ldr(R0, Address(R1, target::Isolate::current_tag_offset()));
// R2: UserTag.
__ ldr(R2, Address(SP, +0 * target::kWordSize));
// Set target::Isolate::current_tag_.
__ str(R2, Address(R1, target::Isolate::current_tag_offset()));
// R2: UserTag's tag.
__ ldr(R2, FieldAddress(R2, target::UserTag::tag_offset()));
// Set target::Isolate::user_tag_.
__ str(R2, Address(R1, target::Isolate::user_tag_offset()));
__ ret();
}
void AsmIntrinsifier::UserTag_defaultTag(Assembler* assembler,
Label* normal_ir_body) {
__ LoadIsolate(R0);

View file

@ -2009,24 +2009,6 @@ void AsmIntrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler,
__ jmp(FieldAddress(EAX, target::Function::entry_point_offset()));
}
// On stack: user tag (+1), return-address (+0).
void AsmIntrinsifier::UserTag_makeCurrent(Assembler* assembler,
Label* normal_ir_body) {
// EDI: Isolate.
__ LoadIsolate(EDI);
// EAX: Current user tag.
__ movl(EAX, Address(EDI, target::Isolate::current_tag_offset()));
// EAX: UserTag.
__ movl(EBX, Address(ESP, +1 * target::kWordSize));
// Set target::Isolate::current_tag_.
__ movl(Address(EDI, target::Isolate::current_tag_offset()), EBX);
// EAX: UserTag's tag.
__ movl(EBX, FieldAddress(EBX, target::UserTag::tag_offset()));
// Set target::Isolate::user_tag_.
__ movl(Address(EDI, target::Isolate::user_tag_offset()), EBX);
__ ret();
}
void AsmIntrinsifier::UserTag_defaultTag(Assembler* assembler,
Label* normal_ir_body) {
__ LoadIsolate(EAX);

View file

@ -2086,24 +2086,6 @@ void AsmIntrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler,
__ jmp(RDI);
}
// On stack: user tag (+1), return-address (+0).
void AsmIntrinsifier::UserTag_makeCurrent(Assembler* assembler,
Label* normal_ir_body) {
// RBX: Isolate.
__ LoadIsolate(RBX);
// RAX: Current user tag.
__ movq(RAX, Address(RBX, target::Isolate::current_tag_offset()));
// R10: UserTag.
__ movq(R10, Address(RSP, +1 * target::kWordSize));
// Set Isolate::current_tag_.
__ movq(Address(RBX, target::Isolate::current_tag_offset()), R10);
// R10: UserTag's tag.
__ movq(R10, FieldAddress(R10, target::UserTag::tag_offset()));
// Set Isolate::user_tag_.
__ movq(Address(RBX, target::Isolate::user_tag_offset()), R10);
__ ret();
}
void AsmIntrinsifier::UserTag_defaultTag(Assembler* assembler,
Label* normal_ir_body) {
__ LoadIsolate(RAX);

View file

@ -377,7 +377,6 @@ namespace dart {
GRAPH_MATH_LIB_INTRINSIC_LIST(V) \
#define DEVELOPER_LIB_INTRINSIC_LIST(V) \
V(_UserTag, makeCurrent, UserTag_makeCurrent, 0x5bd9b88e) \
V(::, _getDefaultTag, UserTag_defaultTag, 0x6c19c8a5) \
V(::, _getCurrentTag, Profiler_getCurrentTag, 0x70ead08e) \
V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, 0xc97aafb3) \

View file

@ -7011,4 +7011,53 @@ DART_EXPORT void Dart_PrepareToAbort() {
OS::PrepareToAbort();
}
DART_EXPORT Dart_Handle Dart_GetCurrentUserTag() {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
DARTSCOPE(thread);
Isolate* isolate = thread->isolate();
return Api::NewHandle(thread, isolate->current_tag());
}
DART_EXPORT Dart_Handle Dart_GetDefaultUserTag() {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
DARTSCOPE(thread);
Isolate* isolate = thread->isolate();
return Api::NewHandle(thread, isolate->default_tag());
}
DART_EXPORT Dart_Handle Dart_NewUserTag(const char* label) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
DARTSCOPE(thread);
if (label == nullptr) {
return Api::NewError(
"Dart_NewUserTag expects argument 'label' to be non-null");
}
const String& value = String::Handle(String::New(label));
return Api::NewHandle(thread, UserTag::New(value));
}
DART_EXPORT Dart_Handle Dart_SetCurrentUserTag(Dart_Handle user_tag) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
DARTSCOPE(thread);
const UserTag& tag = Api::UnwrapUserTagHandle(Z, user_tag);
if (tag.IsNull()) {
RETURN_TYPE_ERROR(Z, user_tag, UserTag);
}
return Api::NewHandle(thread, tag.MakeActive());
}
DART_EXPORT char* Dart_GetUserTagLabel(Dart_Handle user_tag) {
DARTSCOPE(Thread::Current());
const UserTag& tag = Api::UnwrapUserTagHandle(Z, user_tag);
if (tag.IsNull()) {
return nullptr;
}
const String& label = String::Handle(Z, tag.label());
return Utils::StrDup(label.ToCString());
}
} // namespace dart

View file

@ -9363,6 +9363,52 @@ TEST_CASE(Dart_SetFfiNativeResolver_DoesNotResolve) {
"Invalid argument(s): Couldn't resolve function: 'DoesNotResolve'");
}
TEST_CASE(DartAPI_UserTags) {
Dart_Handle default_tag = Dart_GetDefaultUserTag();
EXPECT_VALID(default_tag);
auto default_label =
Utils::CStringUniquePtr(Dart_GetUserTagLabel(default_tag), std::free);
EXPECT_STREQ(default_label.get(), "Default");
Dart_Handle current_tag = Dart_GetCurrentUserTag();
EXPECT(Dart_IdentityEquals(default_tag, current_tag));
auto current_label =
Utils::CStringUniquePtr(Dart_GetUserTagLabel(current_tag), std::free);
EXPECT_STREQ(default_label.get(), current_label.get());
Dart_Handle new_tag = Dart_NewUserTag("Foo");
EXPECT_VALID(new_tag);
auto new_tag_label =
Utils::CStringUniquePtr(Dart_GetUserTagLabel(new_tag), std::free);
EXPECT_STREQ(new_tag_label.get(), "Foo");
Dart_Handle old_tag = Dart_SetCurrentUserTag(new_tag);
EXPECT_VALID(old_tag);
auto old_label =
Utils::CStringUniquePtr(Dart_GetUserTagLabel(old_tag), std::free);
EXPECT_STREQ(old_label.get(), default_label.get());
current_tag = Dart_GetCurrentUserTag();
EXPECT(Dart_IdentityEquals(new_tag, current_tag));
current_label =
Utils::CStringUniquePtr(Dart_GetUserTagLabel(current_tag), std::free);
EXPECT_STREQ(current_label.get(), new_tag_label.get());
EXPECT(Dart_GetUserTagLabel(Dart_Null()) == nullptr);
EXPECT_ERROR(Dart_NewUserTag(nullptr),
"Dart_NewUserTag expects argument 'label' to be non-null");
EXPECT_ERROR(
Dart_SetCurrentUserTag(Dart_Null()),
"Dart_SetCurrentUserTag expects argument 'user_tag' to be non-null");
}
#endif // !PRODUCT
} // namespace dart

View file

@ -25690,10 +25690,25 @@ const char* MirrorReference::ToCString() const {
return "_MirrorReference";
}
void UserTag::MakeActive() const {
UserTagPtr UserTag::MakeActive() const {
Isolate* isolate = Isolate::Current();
ASSERT(isolate != NULL);
UserTag& old = UserTag::Handle(isolate->current_tag());
isolate->set_current_tag(*this);
#if !defined(PRODUCT)
// Notify VM service clients that the current UserTag has changed.
if (Service::profiler_stream.enabled()) {
ServiceEvent event(ServiceEvent::kUserTagChanged);
String& name = String::Handle(old.label());
event.set_previous_tag(name.ToCString());
name ^= label();
event.set_updated_tag(name.ToCString());
Service::HandleEvent(&event);
}
#endif // !defined(PRODUCT)
return old.ptr();
}
UserTagPtr UserTag::New(const String& label, Heap::Space space) {

View file

@ -11559,7 +11559,7 @@ class UserTag : public Instance {
StringPtr label() const { return untag()->label(); }
void MakeActive() const;
UserTagPtr MakeActive() const;
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(UntaggedUserTag));

View file

@ -4605,7 +4605,7 @@ ISOLATE_UNIT_TEST_CASE(PrintJSONPrimitives) {
"vmName\":\"\",\"location\":{\"type\":\"SourceLocation\",\"script\":{"
"\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:"
"developer-patch\\/profiler.dart\",\"_kind\":\"kernel\"},\"tokenPos\":"
"414,\"endTokenPos\":672},\"library\":{\"type\":\"@Library\","
"414,\"endTokenPos\":628},\"library\":{\"type\":\"@Library\","
"\"fixedId\":true,\"id\":\"\",\"name\":\"dart.developer\",\"uri\":"
"\"dart:developer\"}},"
// Handle non-zero identity hash.

View file

@ -128,16 +128,18 @@ StreamInfo Service::heapsnapshot_stream("HeapSnapshot");
StreamInfo Service::logging_stream("Logging");
StreamInfo Service::extension_stream("Extension");
StreamInfo Service::timeline_stream("Timeline");
StreamInfo Service::profiler_stream("Profiler");
const uint8_t* Service::dart_library_kernel_ = NULL;
intptr_t Service::dart_library_kernel_len_ = 0;
static StreamInfo* const streams_[] = {
&Service::vm_stream, &Service::isolate_stream,
&Service::debug_stream, &Service::gc_stream,
&Service::echo_stream, &Service::heapsnapshot_stream,
&Service::logging_stream, &Service::extension_stream,
&Service::timeline_stream};
&Service::vm_stream, &Service::isolate_stream,
&Service::debug_stream, &Service::gc_stream,
&Service::echo_stream, &Service::heapsnapshot_stream,
&Service::logging_stream, &Service::extension_stream,
&Service::timeline_stream, &Service::profiler_stream,
};
bool Service::ListenStream(const char* stream_id) {
if (FLAG_trace_service) {

View file

@ -15,7 +15,7 @@
namespace dart {
#define SERVICE_PROTOCOL_MAJOR_VERSION 3
#define SERVICE_PROTOCOL_MINOR_VERSION 47
#define SERVICE_PROTOCOL_MINOR_VERSION 48
class Array;
class EmbedderServiceHandler;
@ -171,6 +171,7 @@ class Service : public AllStatic {
static StreamInfo logging_stream;
static StreamInfo extension_stream;
static StreamInfo timeline_stream;
static StreamInfo profiler_stream;
static bool ListenStream(const char* stream_id);
static void CancelStream(const char* stream_id);

View file

@ -1,8 +1,8 @@
# Dart VM Service Protocol 3.47
# Dart VM Service Protocol 3.48
> Please post feedback to the [observatory-discuss group][discuss-list]
This document describes of _version 3.47_ of the Dart VM Service Protocol. This
This document describes of _version 3.48_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@ -1477,6 +1477,7 @@ streamId | event types provided
VM | VMUpdate, VMFlagUpdate
Isolate | IsolateStart, IsolateRunnable, IsolateExit, IsolateUpdate, IsolateReload, ServiceExtensionAdded
Debug | PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted, PauseException, PausePostRequest, Resume, BreakpointAdded, BreakpointResolved, BreakpointRemoved, BreakpointUpdated, Inspect, None
Profiler | UserTagChanged
GC | GC
Extension | Extension
Timeline | TimelineEvents, TimelineStreamsSubscriptionUpdate
@ -2154,6 +2155,12 @@ class Event extends Response {
// This is provided for the event kinds:
// HeapSnapshot
bool last [optional];
// The current UserTag label.
string updatedTag [optional];
// The previous UserTag label.
string previousTag [optional];
}
```
@ -2264,6 +2271,9 @@ enum EventKind {
// Notification that a Service has been removed from the Service Protocol
// from another client.
ServiceUnregistered,
// Notification that the UserTag for an isolate has been changed.
UserTagChanged,
}
```
@ -4058,5 +4068,6 @@ version | comments
3.45 | Added `setBreakpointState` RPC and `BreakpointUpdated` event kind.
3.46 | Moved `sourceLocation` property into reference types for `Class`, `Field`, and `Function`.
3.47 | Added `shows` and `hides` properties to `LibraryDependency`.
3.48 | Added `Profiler` stream, `UserTagChanged` event kind, and `updatedTag` and `previousTag` properties to `Event`.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss

View file

@ -28,22 +28,24 @@ ServiceEvent::ServiceEvent(IsolateGroup* isolate_group,
: isolate_(isolate),
isolate_group_(isolate_group),
kind_(event_kind),
flag_name_(NULL),
flag_new_value_(NULL),
embedder_kind_(NULL),
embedder_stream_id_(NULL),
breakpoint_(NULL),
top_frame_(NULL),
timeline_event_block_(NULL),
extension_rpc_(NULL),
exception_(NULL),
reload_error_(NULL),
spawn_token_(NULL),
spawn_error_(NULL),
flag_name_(nullptr),
flag_new_value_(nullptr),
previous_tag_(nullptr),
updated_tag_(nullptr),
embedder_kind_(nullptr),
embedder_stream_id_(nullptr),
breakpoint_(nullptr),
top_frame_(nullptr),
timeline_event_block_(nullptr),
extension_rpc_(nullptr),
exception_(nullptr),
reload_error_(nullptr),
spawn_token_(nullptr),
spawn_error_(nullptr),
at_async_jump_(false),
inspectee_(NULL),
gc_stats_(NULL),
bytes_(NULL),
inspectee_(nullptr),
gc_stats_(nullptr),
bytes_(nullptr),
bytes_length_(0),
timestamp_(OS::GetCurrentTimeMillis()) {
// We should never generate events for the vm isolate as it is never reported
@ -137,6 +139,8 @@ const char* ServiceEvent::KindAsCString() const {
return "TimelineEvents";
case kTimelineStreamSubscriptionsUpdate:
return "TimelineStreamSubscriptionsUpdate";
case kUserTagChanged:
return "UserTagChanged";
default:
UNREACHABLE();
return "Unknown";
@ -187,11 +191,14 @@ const StreamInfo* ServiceEvent::stream_info() const {
return &Service::timeline_stream;
case kEmbedder:
return NULL;
return nullptr;
case kUserTagChanged:
return &Service::profiler_stream;
default:
UNREACHABLE();
return NULL;
return nullptr;
}
}
@ -213,6 +220,10 @@ void ServiceEvent::PrintJSON(JSONStream* js) const {
// For backwards compatibility, "new_value" is also provided.
jsobj.AddProperty("newValue", flag_new_value());
}
if (kind() == kUserTagChanged) {
jsobj.AddProperty("previousTag", previous_tag());
jsobj.AddProperty("updatedTag", updated_tag());
}
if (kind() == kIsolateReload) {
if (reload_error_ == NULL) {
jsobj.AddProperty("status", "success");

View file

@ -60,6 +60,8 @@ class ServiceEvent {
// Sent when SetVMTimelineFlags is called.
kTimelineStreamSubscriptionsUpdate,
kUserTagChanged,
kIllegal,
};
@ -111,6 +113,14 @@ class ServiceEvent {
const char* flag_new_value() const { return flag_new_value_; }
void set_flag_new_value(const char* value) { flag_new_value_ = value; }
const char* previous_tag() const { return previous_tag_; }
void set_previous_tag(const char* previous_tag) {
previous_tag_ = previous_tag;
}
const char* updated_tag() const { return updated_tag_; }
void set_updated_tag(const char* updated_tag) { updated_tag_ = updated_tag; }
const char* embedder_kind() const { return embedder_kind_; }
const char* KindAsCString() const;
@ -217,6 +227,8 @@ class ServiceEvent {
EventKind kind_;
const char* flag_name_;
const char* flag_new_value_;
const char* previous_tag_;
const char* updated_tag_;
const char* embedder_kind_;
const char* embedder_stream_id_;
Breakpoint* breakpoint_;

View file

@ -18,7 +18,6 @@ class UserTag {
class _UserTag implements UserTag {
factory _UserTag(String label) native "UserTag_new";
String get label native "UserTag_label";
@pragma("vm:recognized", "asm-intrinsic")
UserTag makeCurrent() native "UserTag_makeCurrent";
}