Skip to content

Commit

Permalink
[ VM / Service ] Add isolateFlags property to Isolate JSON response
Browse files Browse the repository at this point in the history
Flags that can be set in `Dart_IsolateFlags` are now surfaced via the
Isolate JSON object returned from the service protocol. Currently only
returns boolean flags.

Related: #43588
Change-Id: I54a30155778de8612105eb4a5f60f8a222a086b4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/165403
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
  • Loading branch information
bkonyi authored and commit-bot@chromium.org committed Oct 1, 2020
1 parent fafc1bd commit 45159b1
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 27 deletions.
3 changes: 3 additions & 0 deletions pkg/vm_service/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## 5.3.0
- Added support for `dart:io` extensions version 1.4.
- Update to version `3.40.0` of the spec.
- Added `IsolateFlag` class.
- Added `isolateFlags` property to `Isolate`.

## 5.2.0
- Added support for `dart:io` extensions version 1.3.
Expand Down
15 changes: 15 additions & 0 deletions pkg/vm_service/example/vm_service_assert.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ List<String> assertListOfString(List<String> list) {
return list;
}

List<vms.IsolateFlag> assertListOfIsolateFlag(List<vms.IsolateFlag> list) {
for (vms.IsolateFlag elem in list) {
assertIsolateFlag(elem);
}
return list;
}

String assertString(String obj) {
assertNotNull(obj);
if (obj.isEmpty) throw 'expected non-zero length string';
Expand Down Expand Up @@ -667,6 +674,7 @@ vms.Isolate assertIsolate(vms.Isolate obj) {
assertString(obj.number);
assertString(obj.name);
assertBool(obj.isSystemIsolate);
assertListOfIsolateFlag(obj.isolateFlags);
assertInt(obj.startTime);
assertBool(obj.runnable);
assertInt(obj.livePorts);
Expand All @@ -678,6 +686,13 @@ vms.Isolate assertIsolate(vms.Isolate obj) {
return obj;
}

vms.IsolateFlag assertIsolateFlag(vms.IsolateFlag obj) {
assertNotNull(obj);
assertString(obj.name);
assertString(obj.valueAsString);
return obj;
}

vms.IsolateGroupRef assertIsolateGroupRef(vms.IsolateGroupRef obj) {
assertNotNull(obj);
assertString(obj.type);
Expand Down
1 change: 1 addition & 0 deletions pkg/vm_service/java/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ src/org/dartlang/vm/service/element/InstanceKind.java
src/org/dartlang/vm/service/element/InstanceRef.java
src/org/dartlang/vm/service/element/InstanceSet.java
src/org/dartlang/vm/service/element/Isolate.java
src/org/dartlang/vm/service/element/IsolateFlag.java
src/org/dartlang/vm/service/element/IsolateGroup.java
src/org/dartlang/vm/service/element/IsolateGroupRef.java
src/org/dartlang/vm/service/element/IsolateRef.java
Expand Down
2 changes: 1 addition & 1 deletion pkg/vm_service/java/version.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=3.39
version=3.40
45 changes: 44 additions & 1 deletion pkg/vm_service/lib/src/vm_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export 'snapshot_graph.dart'
HeapSnapshotObjectNoData,
HeapSnapshotObjectNullData;

const String vmServiceVersion = '3.39.0';
const String vmServiceVersion = '3.40.0';

/// @optional
const String optional = 'optional';
Expand Down Expand Up @@ -139,6 +139,7 @@ Map<String, Function> _typeFactories = {
'Instance': Instance.parse,
'@Isolate': IsolateRef.parse,
'Isolate': Isolate.parse,
'IsolateFlag': IsolateFlag.parse,
'@IsolateGroup': IsolateGroupRef.parse,
'IsolateGroup': IsolateGroup.parse,
'InboundReferences': InboundReferences.parse,
Expand Down Expand Up @@ -4745,6 +4746,10 @@ class Isolate extends Response implements IsolateRef {
/// internal use. If `false`, this isolate is likely running user code.
bool isSystemIsolate;

/// The list of isolate flags provided to this isolate. See Dart_IsolateFlags
/// in dart_api.h for the list of accepted isolate flags.
List<IsolateFlag> isolateFlags;

/// The time that the VM started in milliseconds since the epoch.
///
/// Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
Expand Down Expand Up @@ -4794,6 +4799,7 @@ class Isolate extends Response implements IsolateRef {
@required this.number,
@required this.name,
@required this.isSystemIsolate,
@required this.isolateFlags,
@required this.startTime,
@required this.runnable,
@required this.livePorts,
Expand All @@ -4812,6 +4818,8 @@ class Isolate extends Response implements IsolateRef {
number = json['number'];
name = json['name'];
isSystemIsolate = json['isSystemIsolate'];
isolateFlags = List<IsolateFlag>.from(
createServiceObject(json['isolateFlags'], const ['IsolateFlag']) ?? []);
startTime = json['startTime'];
runnable = json['runnable'];
livePorts = json['livePorts'];
Expand All @@ -4838,6 +4846,7 @@ class Isolate extends Response implements IsolateRef {
'number': number,
'name': name,
'isSystemIsolate': isSystemIsolate,
'isolateFlags': isolateFlags.map((f) => f.toJson()).toList(),
'startTime': startTime,
'runnable': runnable,
'livePorts': livePorts,
Expand All @@ -4861,6 +4870,40 @@ class Isolate extends Response implements IsolateRef {
String toString() => '[Isolate]';
}

/// Represents the value of a single isolate flag. See [Isolate].
class IsolateFlag {
static IsolateFlag parse(Map<String, dynamic> json) =>
json == null ? null : IsolateFlag._fromJson(json);

/// The name of the flag.
String name;

/// The value of this flag as a string.
String valueAsString;

IsolateFlag({
@required this.name,
@required this.valueAsString,
});

IsolateFlag._fromJson(Map<String, dynamic> json) {
name = json['name'];
valueAsString = json['valueAsString'];
}

Map<String, dynamic> toJson() {
var json = <String, dynamic>{};
json.addAll({
'name': name,
'valueAsString': valueAsString,
});
return json;
}

String toString() =>
'[IsolateFlag name: ${name}, valueAsString: ${valueAsString}]';
}

/// `IsolateGroupRef` is a reference to an `IsolateGroup` object.
class IsolateGroupRef extends Response {
static IsolateGroupRef parse(Map<String, dynamic> json) =>
Expand Down
60 changes: 60 additions & 0 deletions pkg/vm_service/test/get_isolate_rpc_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) 2020, 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 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';

import 'common/test_helper.dart';

var tests = <VMTest>[
(VmService service) async {
final vm = await service.getVM();
final result = await service.getIsolate(vm.isolates.first.id);
expect(result.id, startsWith('isolates/'));
expect(result.number, isNotNull);
expect(result.isolateFlags, isNotNull);
expect(result.isolateFlags.length, isPositive);
expect(result.isSystemIsolate, isFalse);
expect(result.json['_originNumber'], result.number);
expect(result.startTime, isPositive);
expect(result.livePorts, isPositive);
expect(result.pauseOnExit, isFalse);
expect(result.pauseEvent.type, 'Event');
expect(result.error, isNull);
expect(result.json['_numZoneHandles'], isPositive);
expect(result.json['_numScopedHandles'], isPositive);
expect(result.rootLib, isNotNull);
expect(result.libraries.length, isPositive);
expect(result.libraries[0], isNotNull);
expect(result.breakpoints.length, isZero);
expect(result.json['_heaps']['new']['type'], 'HeapSpace');
expect(result.json['_heaps']['old']['type'], 'HeapSpace');
},

(VmService service) async {
bool caughtException;
try {
await service.getIsolate('badid');
expect(false, isTrue, reason: 'Unreachable');
} on RPCError catch (e) {
caughtException = true;
expect(e.code, equals(RPCError.kInvalidParams));
expect(e.details, "getIsolate: invalid 'isolateId' parameter: badid");
}
expect(caughtException, isTrue);
},

// Plausible isolate id, not found.
(VmService service) async {
try {
await service.getIsolate('isolates/9999999999');
fail('successfully got isolate with bad ID');
} on SentinelException catch (e) {
expect(e.sentinel.kind, 'Collected');
expect(e.sentinel.valueAsString, '<collected>');
}
},
];

main(args) async => runVMTests(args, tests);
2 changes: 2 additions & 0 deletions pkg/vm_service/test/server_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ void main() {
startTime: 1,
runnable: true,
livePorts: 2,
isolateFlags: [],
pauseOnExit: false,
pauseEvent: Event(
kind: EventKind.kResume,
Expand Down Expand Up @@ -78,6 +79,7 @@ void main() {
startTime: 1,
runnable: true,
livePorts: 2,
isolateFlags: [],
pauseOnExit: false,
pauseEvent: Event(
kind: EventKind.kResume,
Expand Down
7 changes: 7 additions & 0 deletions pkg/vm_service/tool/dart/generate_dart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,13 @@ List<String> assertListOfString(List<String> list) {
return list;
}
List<vms.IsolateFlag> assertListOfIsolateFlag(List<vms.IsolateFlag> list) {
for (vms.IsolateFlag elem in list) {
assertIsolateFlag(elem);
}
return list;
}
String assertString(String obj) {
assertNotNull(obj);
if (obj.isEmpty) throw 'expected non-zero length string';
Expand Down
2 changes: 2 additions & 0 deletions runtime/observatory/tests/service/get_isolate_rpc_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ var tests = <VMTest>[
expect(result['type'], equals('Isolate'));
expect(result['id'], startsWith('isolates/'));
expect(result['number'], isA<String>());
expect(result['isolateFlags'], isA<List>());
expect(result['isolateFlags'].length, isPositive);
expect(result['isSystemIsolate'], isFalse);
expect(result['_originNumber'], equals(result['number']));
expect(result['startTime'], isPositive);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var tests = <VMTest>[
var result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
expect(result['major'], equals(3));
expect(result['minor'], equals(39));
expect(result['minor'], equals(40));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},
Expand Down
40 changes: 27 additions & 13 deletions runtime/vm/isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1511,29 +1511,24 @@ void Isolate::FlagsInitialize(Dart_IsolateFlags* api_flags) {
api_flags->version = DART_FLAGS_CURRENT_VERSION;
#define INIT_FROM_FLAG(when, name, bitname, isolate_flag, flag) \
api_flags->isolate_flag = flag;
ISOLATE_FLAG_LIST(INIT_FROM_FLAG)
BOOL_ISOLATE_FLAG_LIST(INIT_FROM_FLAG)
#undef INIT_FROM_FLAG
api_flags->entry_points = NULL;
api_flags->load_vmservice_library = false;
api_flags->copy_parent_code = false;
api_flags->null_safety = false;
api_flags->is_system_isolate = false;
}

void Isolate::FlagsCopyTo(Dart_IsolateFlags* api_flags) const {
api_flags->version = DART_FLAGS_CURRENT_VERSION;
#define INIT_FROM_FIELD(when, name, bitname, isolate_flag, flag) \
api_flags->isolate_flag = name();
ISOLATE_FLAG_LIST(INIT_FROM_FIELD)
BOOL_ISOLATE_FLAG_LIST(INIT_FROM_FIELD)
#undef INIT_FROM_FIELD
api_flags->entry_points = NULL;
api_flags->load_vmservice_library = should_load_vmservice();
api_flags->copy_parent_code = false;
api_flags->null_safety = null_safety();
api_flags->is_system_isolate = is_system_isolate();
}

void Isolate::FlagsCopyFrom(const Dart_IsolateFlags& api_flags) {
const bool copy_parent_code_ = copy_parent_code();
#if defined(DART_PRECOMPILER)
#define FLAG_FOR_PRECOMPILER(action) action
#else
Expand All @@ -1552,16 +1547,16 @@ void Isolate::FlagsCopyFrom(const Dart_IsolateFlags& api_flags) {
FLAG_FOR_##when(isolate_flags_ = bitname##Bit::update( \
api_flags.isolate_flag, isolate_flags_));

ISOLATE_FLAG_LIST(SET_FROM_FLAG)

BOOL_ISOLATE_FLAG_LIST(SET_FROM_FLAG)
isolate_flags_ = CopyParentCodeBit::update(copy_parent_code_, isolate_flags_);
// Needs to be called manually, otherwise we don't set the null_safety_set
// bit.
set_null_safety(api_flags.null_safety);
#undef FLAG_FOR_NONPRODUCT
#undef FLAG_FOR_PRECOMPILER
#undef FLAG_FOR_PRODUCT
#undef SET_FROM_FLAG

set_should_load_vmservice(api_flags.load_vmservice_library);
set_null_safety(api_flags.null_safety);
set_is_system_isolate(api_flags.is_system_isolate);
// Copy entry points list.
ASSERT(embedder_entry_points_ == NULL);
if (api_flags.entry_points != NULL) {
Expand Down Expand Up @@ -3088,6 +3083,25 @@ void Isolate::PrintJSON(JSONStream* stream, bool ref) {
heap()->PrintToJSONObject(Heap::kOld, &jsheap);
}

{
// Stringification macros
// See https://gcc.gnu.org/onlinedocs/gcc-4.8.5/cpp/Stringification.html
#define TO_STRING(s) STR(s)
#define STR(s) #s

#define ADD_ISOLATE_FLAGS(when, name, bitname, isolate_flag_name, flag_name) \
{ \
JSONObject jsflag(&jsflags); \
jsflag.AddProperty("name", TO_STRING(name)); \
jsflag.AddProperty("valueAsString", name() ? "true" : "false"); \
}
JSONArray jsflags(&jsobj, "isolateFlags");
BOOL_ISOLATE_FLAG_LIST(ADD_ISOLATE_FLAGS)
#undef ADD_ISOLATE_FLAGS
#undef TO_STRING
#undef STR
}

jsobj.AddProperty("runnable", is_runnable());
jsobj.AddProperty("livePorts", message_handler()->live_ports());
jsobj.AddProperty("pauseOnExit", message_handler()->should_pause_on_exit());
Expand Down
Loading

0 comments on commit 45159b1

Please sign in to comment.