From d5118d5fc83db077f23b8f7dd5d489634199ad1a Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Thu, 29 Oct 2020 02:52:03 +0000 Subject: [PATCH] Reland "[ Service / dart:isolate ] Added getPorts RPC and 'debugName' optional" This reverts commit f78c40e32a5b52f6b013a61f1548e0da5a9089a8. Change-Id: Id838b39afcb371d3b50f0009322ecf0fb2080894 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169461 Reviewed-by: Ryan Macnak Commit-Queue: Ben Konyi --- CHANGELOG.md | 10 +- pkg/vm_service/CHANGELOG.md | 9 +- pkg/vm_service/example/vm_service_assert.dart | 8 ++ pkg/vm_service/java/.gitignore | 2 + pkg/vm_service/java/version.properties | 2 +- pkg/vm_service/lib/src/vm_service.dart | 116 +++++++++++++++++- pkg/vm_service/pubspec.yaml | 2 +- runtime/lib/isolate.cc | 5 +- runtime/lib/stacktrace.cc | 8 ++ runtime/lib/stacktrace.h | 3 + .../lib/src/models/objects/instance.dart | 3 + .../observatory/lib/src/service/object.dart | 2 + .../service/get_ports_public_rpc_test.dart | 50 ++++++++ .../tests/service/get_version_rpc_test.dart | 12 +- .../lib/src/models/objects/instance.dart | 3 + .../observatory_2/lib/src/service/object.dart | 2 + .../service_2/get_ports_public_rpc_test.dart | 50 ++++++++ .../tests/service_2/get_version_rpc_test.dart | 2 +- runtime/vm/bootstrap_natives.h | 2 +- .../vm/compiler/runtime_offsets_extracted.h | 28 ++--- runtime/vm/dart_entry.cc | 25 ++++ runtime/vm/dart_entry.h | 3 + runtime/vm/isolate.cc | 5 +- runtime/vm/object.cc | 7 ++ runtime/vm/object.h | 7 ++ runtime/vm/object_service.cc | 10 +- runtime/vm/object_store.h | 1 + runtime/vm/raw_object.h | 4 +- runtime/vm/raw_object_fields.cc | 2 + runtime/vm/service.cc | 34 ++++- runtime/vm/service.h | 2 +- runtime/vm/service/service.md | 70 ++++++++++- runtime/vm/symbols.h | 1 + sdk/lib/_internal/vm/lib/isolate_patch.dart | 52 ++++---- sdk/lib/isolate/isolate.dart | 11 +- 35 files changed, 489 insertions(+), 64 deletions(-) create mode 100644 runtime/observatory/tests/service/get_ports_public_rpc_test.dart create mode 100644 runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e40af495d4..2611829b62b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,14 @@ #### `dart:io` -* `HttpRequest` will now correctly follow HTTP 308 redirects - (`HttpStatus.permanentRedirect`). +* `HttpRequest` will now correctly follow HTTP 308 redirects + (`HttpStatus.permanentRedirect`). + +#### `dart:isolate` + +* Added `debugName` positional parameter to `ReceivePort` and `RawReceivePort` + constructors, a name which can be associated with the port and displayed in + tooling. ### Dart VM diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md index 9299ed513d8..bbb753e69c6 100644 --- a/pkg/vm_service/CHANGELOG.md +++ b/pkg/vm_service/CHANGELOG.md @@ -1,4 +1,12 @@ # Changelog + +## 5.4.0 +- Update to version `3.41.0` of the spec. +- Added `PortList` class. +- Added `getPorts` RPC. +- Added optional properties `portId`, `allocationLocation`, and `debugName` to + `InstanceRef` and `Instance`. + ## 5.3.1 - Rename `State` class to `_State` to avoid class name conflicts with Flutter. @@ -6,7 +14,6 @@ - Added support for `dart:io` extensions version 1.5. - Added combination getter/setter `socketProfilingEnabled`. - Deprecated `startSocketProfiling` and `pauseSocketProfiling`. -- 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`. diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart index e2ae6d1a49a..617bd7c6df3 100644 --- a/pkg/vm_service/example/vm_service_assert.dart +++ b/pkg/vm_service/example/vm_service_assert.dart @@ -192,6 +192,7 @@ String assertInstanceKind(String obj) { if (obj == "MirrorReference") return obj; if (obj == "Null") return obj; if (obj == "PlainInstance") return obj; + if (obj == "ReceivePort") return obj; if (obj == "RegExp") return obj; if (obj == "StackTrace") return obj; if (obj == "String") return obj; @@ -912,6 +913,13 @@ vms.Obj assertObj(vms.Obj obj) { return obj; } +vms.PortList assertPortList(vms.PortList obj) { + assertNotNull(obj); + assertString(obj.type); + assertListOfInstanceRef(obj.ports); + return obj; +} + vms.ProfileFunction assertProfileFunction(vms.ProfileFunction obj) { assertNotNull(obj); assertString(obj.kind); diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore index ae6691fc2e1..8803d45ccc3 100644 --- a/pkg/vm_service/java/.gitignore +++ b/pkg/vm_service/java/.gitignore @@ -25,6 +25,7 @@ src/org/dartlang/vm/service/consumer/GetStackConsumer.java src/org/dartlang/vm/service/consumer/InvokeConsumer.java src/org/dartlang/vm/service/consumer/KillConsumer.java src/org/dartlang/vm/service/consumer/PauseConsumer.java +src/org/dartlang/vm/service/consumer/PortListConsumer.java src/org/dartlang/vm/service/consumer/ProcessMemoryUsageConsumer.java src/org/dartlang/vm/service/consumer/ProtocolListConsumer.java src/org/dartlang/vm/service/consumer/ReloadSourcesConsumer.java @@ -95,6 +96,7 @@ src/org/dartlang/vm/service/element/Null.java src/org/dartlang/vm/service/element/NullRef.java src/org/dartlang/vm/service/element/Obj.java src/org/dartlang/vm/service/element/ObjRef.java +src/org/dartlang/vm/service/element/PortList.java src/org/dartlang/vm/service/element/ProcessMemoryItem.java src/org/dartlang/vm/service/element/ProcessMemoryUsage.java src/org/dartlang/vm/service/element/ProfileFunction.java diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties index d0564a6aa9b..ae41aeb649f 100644 --- a/pkg/vm_service/java/version.properties +++ b/pkg/vm_service/java/version.properties @@ -1 +1 @@ -version=3.40 +version=3.41 diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart index fd20c5bef0e..4dfc752d4a5 100644 --- a/pkg/vm_service/lib/src/vm_service.dart +++ b/pkg/vm_service/lib/src/vm_service.dart @@ -28,7 +28,7 @@ export 'snapshot_graph.dart' HeapSnapshotObjectNoData, HeapSnapshotObjectNullData; -const String vmServiceVersion = '3.40.0'; +const String vmServiceVersion = '3.41.0'; /// @optional const String optional = 'optional'; @@ -157,6 +157,7 @@ Map _typeFactories = { 'Null': NullVal.parse, '@Object': ObjRef.parse, 'Object': Obj.parse, + 'PortList': PortList.parse, 'ProfileFunction': ProfileFunction.parse, 'ProtocolList': ProtocolList.parse, 'Protocol': Protocol.parse, @@ -209,6 +210,7 @@ Map> _methodReturnTypes = { 'getIsolateGroupMemoryUsage': const ['MemoryUsage'], 'getScripts': const ['ScriptList'], 'getObject': const ['Obj'], + 'getPorts': const ['PortList'], 'getRetainingPath': const ['RetainingPath'], 'getProcessMemoryUsage': const ['ProcessMemoryUsage'], 'getStack': const ['Stack'], @@ -688,6 +690,12 @@ abstract class VmServiceInterface { int count, }); + /// The `getPorts` RPC is used to retrieve the list of `ReceivePort` instances + /// for a given isolate. + /// + /// See [PortList]. + Future getPorts(String isolateId); + /// The `getRetainingPath` RPC is used to lookup a path from an object /// specified by `targetId` to a GC root (i.e., the object which is preventing /// this object from being garbage collected). @@ -1318,6 +1326,11 @@ class VmServerConnection { count: params['count'], ); break; + case 'getPorts': + response = await _serviceImplementation.getPorts( + params['isolateId'], + ); + break; case 'getRetainingPath': response = await _serviceImplementation.getRetainingPath( params['isolateId'], @@ -1770,6 +1783,10 @@ class VmService implements VmServiceInterface { if (count != null) 'count': count, }); + @override + Future getPorts(String isolateId) => + _call('getPorts', {'isolateId': isolateId}); + @override Future getRetainingPath( String isolateId, String targetId, int limit) => @@ -2432,6 +2449,9 @@ class InstanceKind { /// An instance of the Dart class BoundedType. static const String kBoundedType = 'BoundedType'; + + /// An instance of the Dart class ReceivePort. + static const String kReceivePort = 'ReceivePort'; } /// A `SentinelKind` is used to distinguish different kinds of `Sentinel` @@ -4239,6 +4259,27 @@ class InstanceRef extends ObjRef { @optional ContextRef closureContext; + /// The port ID for a ReceivePort. + /// + /// Provided for instance kinds: + /// - ReceivePort + @optional + int portId; + + /// The stack trace associated with the allocation of a ReceivePort. + /// + /// Provided for instance kinds: + /// - ReceivePort + @optional + InstanceRef allocationLocation; + + /// A name associated with a ReceivePort used for debugging purposes. + /// + /// Provided for instance kinds: + /// - ReceivePort + @optional + String debugName; + InstanceRef({ @required this.kind, @required this.classRef, @@ -4252,6 +4293,9 @@ class InstanceRef extends ObjRef { this.pattern, this.closureFunction, this.closureContext, + this.portId, + this.allocationLocation, + this.debugName, }) : super(id: id); InstanceRef._fromJson(Map json) : super._fromJson(json) { @@ -4269,6 +4313,10 @@ class InstanceRef extends ObjRef { createServiceObject(json['closureFunction'], const ['FuncRef']); closureContext = createServiceObject(json['closureContext'], const ['ContextRef']); + portId = json['portId']; + allocationLocation = + createServiceObject(json['allocationLocation'], const ['InstanceRef']); + debugName = json['debugName']; } @override @@ -4288,6 +4336,9 @@ class InstanceRef extends ObjRef { _setIfNotNull(json, 'pattern', pattern?.toJson()); _setIfNotNull(json, 'closureFunction', closureFunction?.toJson()); _setIfNotNull(json, 'closureContext', closureContext?.toJson()); + _setIfNotNull(json, 'portId', portId); + _setIfNotNull(json, 'allocationLocation', allocationLocation?.toJson()); + _setIfNotNull(json, 'debugName', debugName); return json; } @@ -4318,6 +4369,7 @@ class Instance extends Obj implements InstanceRef { /// - Double (suitable for passing to Double.parse()) /// - Int (suitable for passing to int.parse()) /// - String (value may be truncated) + /// - StackTrace @optional String valueAsString; @@ -4554,6 +4606,27 @@ class Instance extends Obj implements InstanceRef { @optional InstanceRef bound; + /// The port ID for a ReceivePort. + /// + /// Provided for instance kinds: + /// - ReceivePort + @optional + int portId; + + /// The stack trace associated with the allocation of a ReceivePort. + /// + /// Provided for instance kinds: + /// - ReceivePort + @optional + InstanceRef allocationLocation; + + /// A name associated with a ReceivePort used for debugging purposes. + /// + /// Provided for instance kinds: + /// - ReceivePort + @optional + String debugName; + Instance({ @required this.kind, @required this.classRef, @@ -4582,6 +4655,9 @@ class Instance extends Obj implements InstanceRef { this.parameterIndex, this.targetType, this.bound, + this.portId, + this.allocationLocation, + this.debugName, }) : super(id: id); Instance._fromJson(Map json) : super._fromJson(json) { @@ -4627,6 +4703,10 @@ class Instance extends Obj implements InstanceRef { parameterIndex = json['parameterIndex']; targetType = createServiceObject(json['targetType'], const ['InstanceRef']); bound = createServiceObject(json['bound'], const ['InstanceRef']); + portId = json['portId']; + allocationLocation = + createServiceObject(json['allocationLocation'], const ['InstanceRef']); + debugName = json['debugName']; } @override @@ -4663,6 +4743,9 @@ class Instance extends Obj implements InstanceRef { _setIfNotNull(json, 'parameterIndex', parameterIndex); _setIfNotNull(json, 'targetType', targetType?.toJson()); _setIfNotNull(json, 'bound', bound?.toJson()); + _setIfNotNull(json, 'portId', portId); + _setIfNotNull(json, 'allocationLocation', allocationLocation?.toJson()); + _setIfNotNull(json, 'debugName', debugName); return json; } @@ -5743,6 +5826,37 @@ class Obj extends Response implements ObjRef { String toString() => '[Obj type: ${type}, id: ${id}]'; } +/// A `PortList` contains a list of ports associated with some isolate. +/// +/// See [getPort]. +class PortList extends Response { + static PortList parse(Map json) => + json == null ? null : PortList._fromJson(json); + + List ports; + + PortList({ + @required this.ports, + }); + + PortList._fromJson(Map json) : super._fromJson(json) { + ports = List.from( + createServiceObject(json['ports'], const ['InstanceRef']) ?? []); + } + + @override + Map toJson() { + var json = {}; + json['type'] = 'PortList'; + json.addAll({ + 'ports': ports.map((f) => f.toJson()).toList(), + }); + return json; + } + + String toString() => '[PortList type: ${type}, ports: ${ports}]'; +} + /// A `ProfileFunction` contains profiling information about a Dart or native /// function. /// diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml index 7d0d07a3845..0c77a68f57a 100644 --- a/pkg/vm_service/pubspec.yaml +++ b/pkg/vm_service/pubspec.yaml @@ -2,7 +2,7 @@ name: vm_service description: >- A library to communicate with a service implementing the Dart VM service protocol. -version: 5.3.1 +version: 5.4.0 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc index 4b381cbb628..905cb26c9e4 100644 --- a/runtime/lib/isolate.cc +++ b/runtime/lib/isolate.cc @@ -51,11 +51,12 @@ DEFINE_NATIVE_ENTRY(CapabilityImpl_get_hashcode, 0, 1) { return Smi::New(hash); } -DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 0, 1) { +DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 0, 2) { ASSERT( TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull()); + GET_NON_NULL_NATIVE_ARGUMENT(String, debug_name, arguments->NativeArgAt(1)); Dart_Port port_id = PortMap::CreatePort(isolate->message_handler()); - return ReceivePort::New(port_id, false /* not control port */); + return ReceivePort::New(port_id, debug_name, false /* not control port */); } DEFINE_NATIVE_ENTRY(RawReceivePortImpl_get_id, 0, 1) { diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc index 43383d4adeb..3eabaf41f58 100644 --- a/runtime/lib/stacktrace.cc +++ b/runtime/lib/stacktrace.cc @@ -214,4 +214,12 @@ const StackTrace& GetCurrentStackTrace(int skip_frames) { return stacktrace; } +bool HasStack() { + Thread* thread = Thread::Current(); + StackFrameIterator frames(ValidationPolicy::kDontValidateFrames, thread, + StackFrameIterator::kNoCrossThreadIteration); + StackFrame* frame = frames.NextFrame(); + return frame != nullptr; +} + } // namespace dart diff --git a/runtime/lib/stacktrace.h b/runtime/lib/stacktrace.h index 9c8abae72e4..a804d62bcc3 100644 --- a/runtime/lib/stacktrace.h +++ b/runtime/lib/stacktrace.h @@ -21,6 +21,9 @@ const StackTrace& GetCurrentStackTrace(int skip_frames); // Creates a StackTrace object to be attached to an exception. StackTracePtr GetStackTraceForException(); +// Returns false if there is no Dart stack available. +bool HasStack(); + } // namespace dart #endif // RUNTIME_LIB_STACKTRACE_H_ diff --git a/runtime/observatory/lib/src/models/objects/instance.dart b/runtime/observatory/lib/src/models/objects/instance.dart index ab8d6d69291..a0400c527b9 100644 --- a/runtime/observatory/lib/src/models/objects/instance.dart +++ b/runtime/observatory/lib/src/models/objects/instance.dart @@ -120,6 +120,9 @@ enum InstanceKind { /// An instance of the Dart class TypeRef. typeRef, + + /// An instance of the Dart class RawReceivePort + receivePort, } bool isTypedData(InstanceKind? kind) { diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart index 4f9ead00f2e..55c9d1367f5 100644 --- a/runtime/observatory/lib/src/service/object.dart +++ b/runtime/observatory/lib/src/service/object.dart @@ -2781,6 +2781,8 @@ M.InstanceKind stringToInstanceKind(String s) { return M.InstanceKind.typeParameter; case 'TypeRef': return M.InstanceKind.typeRef; + case 'ReceivePort': + return M.InstanceKind.receivePort; } var message = 'Unrecognized instance kind: $s'; Logger.root.severe(message); diff --git a/runtime/observatory/tests/service/get_ports_public_rpc_test.dart b/runtime/observatory/tests/service/get_ports_public_rpc_test.dart new file mode 100644 index 00000000000..cc511f79d60 --- /dev/null +++ b/runtime/observatory/tests/service/get_ports_public_rpc_test.dart @@ -0,0 +1,50 @@ +// 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 'dart:isolate' hide Isolate; +import 'package:observatory/service_io.dart'; +import 'package:test/test.dart'; + +import 'test_helper.dart'; + +var port1; +var port2; +var port3; + +void warmup() { + port1 = RawReceivePort(null, 'port1'); + port2 = RawReceivePort((_) {}); + port3 = RawReceivePort((_) {}, 'port3'); + port3.close(); + RawReceivePort((_) {}, 'port4'); +} + +int countNameMatches(ports, name) { + var matches = 0; + for (var port in ports) { + if (port['debugName'] == name) { + matches++; + } + } + return matches; +} + +final tests = [ + (Isolate isolate) async { + dynamic result = await isolate.invokeRpcNoUpgrade('getPorts', {}); + expect(result['type'], 'PortList'); + expect(result['ports'], isList); + final ports = result['ports']; + // There are at least three ports: the three created in warm up that + // weren't closed. Some OSes will have other ports open but we do not try + // and test for these. + expect(ports.length, greaterThanOrEqualTo(3)); + expect(countNameMatches(ports, 'port1'), 1); + expect(countNameMatches(ports, 'port3'), 0); + expect(countNameMatches(ports, 'port4'), 1); + expect(countNameMatches(ports, ''), greaterThanOrEqualTo(1)); + }, +]; + +main(args) async => runIsolateTests(args, tests, testeeBefore: warmup); diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart index 8b563937268..c8b0244d824 100644 --- a/runtime/observatory/tests/service/get_version_rpc_test.dart +++ b/runtime/observatory/tests/service/get_version_rpc_test.dart @@ -9,12 +9,12 @@ import 'test_helper.dart'; var tests = [ (VM vm) async { - var result = await vm.invokeRpcNoUpgrade('getVersion', {}); - expect(result['type'], equals('Version')); - expect(result['major'], equals(3)); - expect(result['minor'], equals(40)); - expect(result['_privateMajor'], equals(0)); - expect(result['_privateMinor'], equals(0)); + final result = await vm.invokeRpcNoUpgrade('getVersion', {}); + expect(result['type'], 'Version'); + expect(result['major'], 3); + expect(result['minor'], 41); + expect(result['_privateMajor'], 0); + expect(result['_privateMinor'], 0); }, ]; diff --git a/runtime/observatory_2/lib/src/models/objects/instance.dart b/runtime/observatory_2/lib/src/models/objects/instance.dart index 66965e9889a..e52cdd7173f 100644 --- a/runtime/observatory_2/lib/src/models/objects/instance.dart +++ b/runtime/observatory_2/lib/src/models/objects/instance.dart @@ -120,6 +120,9 @@ enum InstanceKind { /// An instance of the Dart class TypeRef. typeRef, + + /// An instance of the Dart class RawReceivePort + receivePort, } bool isTypedData(InstanceKind kind) { diff --git a/runtime/observatory_2/lib/src/service/object.dart b/runtime/observatory_2/lib/src/service/object.dart index 1bd33fbce1b..fe4027b3dc1 100644 --- a/runtime/observatory_2/lib/src/service/object.dart +++ b/runtime/observatory_2/lib/src/service/object.dart @@ -2790,6 +2790,8 @@ M.InstanceKind stringToInstanceKind(String s) { return M.InstanceKind.typeParameter; case 'TypeRef': return M.InstanceKind.typeRef; + case 'ReceivePort': + return M.InstanceKind.receivePort; } var message = 'Unrecognized instance kind: $s'; Logger.root.severe(message); diff --git a/runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart new file mode 100644 index 00000000000..179823fa0e8 --- /dev/null +++ b/runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart @@ -0,0 +1,50 @@ +// 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 'dart:isolate' hide Isolate; +import 'package:observatory_2/service_io.dart'; +import 'package:test/test.dart'; + +import 'test_helper.dart'; + +var port1; +var port2; +var port3; + +void warmup() { + port1 = RawReceivePort(null, 'port1'); + port2 = RawReceivePort((_) {}); + port3 = RawReceivePort((_) {}, 'port3'); + port3.close(); + RawReceivePort((_) {}, 'port4'); +} + +int countNameMatches(ports, name) { + var matches = 0; + for (var port in ports) { + if (port['debugName'] == name) { + matches++; + } + } + return matches; +} + +final tests = [ + (Isolate isolate) async { + dynamic result = await isolate.invokeRpcNoUpgrade('getPorts', {}); + expect(result['type'], 'PortList'); + expect(result['ports'], isList); + final ports = result['ports']; + // There are at least three ports: the three created in warm up that + // weren't closed. Some OSes will have other ports open but we do not try + // and test for these. + expect(ports.length, greaterThanOrEqualTo(3)); + expect(countNameMatches(ports, 'port1'), 1); + expect(countNameMatches(ports, 'port3'), 0); + expect(countNameMatches(ports, 'port4'), 1); + expect(countNameMatches(ports, ''), greaterThanOrEqualTo(1)); + }, +]; + +main(args) async => runIsolateTests(args, tests, testeeBefore: warmup); diff --git a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart index d5450e50a0a..df37cb947ad 100644 --- a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart +++ b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart @@ -12,7 +12,7 @@ var tests = [ var result = await vm.invokeRpcNoUpgrade('getVersion', {}); expect(result['type'], equals('Version')); expect(result['major'], equals(3)); - expect(result['minor'], equals(40)); + expect(result['minor'], equals(41)); expect(result['_privateMajor'], equals(0)); expect(result['_privateMinor'], equals(0)); }, diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h index b7ef75aade0..8b15f7b2c04 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -54,7 +54,7 @@ namespace dart { V(CapabilityImpl_factory, 1) \ V(CapabilityImpl_equals, 2) \ V(CapabilityImpl_get_hashcode, 1) \ - V(RawReceivePortImpl_factory, 1) \ + V(RawReceivePortImpl_factory, 2) \ V(RawReceivePortImpl_get_id, 1) \ V(RawReceivePortImpl_get_sendport, 1) \ V(RawReceivePortImpl_closeInternal, 1) \ diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h index 6650cd6945d..52fcd87b01f 100644 --- a/runtime/vm/compiler/runtime_offsets_extracted.h +++ b/runtime/vm/compiler/runtime_offsets_extracted.h @@ -497,7 +497,7 @@ static constexpr dart::compiler::target::word OneByteString_InstanceSize = 12; static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24; static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8; static constexpr dart::compiler::target::word Pointer_InstanceSize = 12; -static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12; +static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20; static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16; static constexpr dart::compiler::target::word RegExp_InstanceSize = 60; static constexpr dart::compiler::target::word Script_InstanceSize = 56; @@ -1017,7 +1017,7 @@ static constexpr dart::compiler::target::word OneByteString_InstanceSize = 16; static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48; static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16; static constexpr dart::compiler::target::word Pointer_InstanceSize = 24; -static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24; +static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40; static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32; static constexpr dart::compiler::target::word RegExp_InstanceSize = 120; static constexpr dart::compiler::target::word Script_InstanceSize = 96; @@ -1528,7 +1528,7 @@ static constexpr dart::compiler::target::word OneByteString_InstanceSize = 12; static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24; static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8; static constexpr dart::compiler::target::word Pointer_InstanceSize = 12; -static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12; +static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20; static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16; static constexpr dart::compiler::target::word RegExp_InstanceSize = 60; static constexpr dart::compiler::target::word Script_InstanceSize = 56; @@ -2049,7 +2049,7 @@ static constexpr dart::compiler::target::word OneByteString_InstanceSize = 16; static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48; static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16; static constexpr dart::compiler::target::word Pointer_InstanceSize = 24; -static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24; +static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40; static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32; static constexpr dart::compiler::target::word RegExp_InstanceSize = 120; static constexpr dart::compiler::target::word Script_InstanceSize = 96; @@ -2559,7 +2559,7 @@ static constexpr dart::compiler::target::word OneByteString_InstanceSize = 12; static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24; static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8; static constexpr dart::compiler::target::word Pointer_InstanceSize = 12; -static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12; +static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20; static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16; static constexpr dart::compiler::target::word RegExp_InstanceSize = 60; static constexpr dart::compiler::target::word Script_InstanceSize = 56; @@ -3073,7 +3073,7 @@ static constexpr dart::compiler::target::word OneByteString_InstanceSize = 16; static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48; static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16; static constexpr dart::compiler::target::word Pointer_InstanceSize = 24; -static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24; +static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40; static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32; static constexpr dart::compiler::target::word RegExp_InstanceSize = 120; static constexpr dart::compiler::target::word Script_InstanceSize = 96; @@ -3578,7 +3578,7 @@ static constexpr dart::compiler::target::word OneByteString_InstanceSize = 12; static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24; static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8; static constexpr dart::compiler::target::word Pointer_InstanceSize = 12; -static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12; +static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20; static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16; static constexpr dart::compiler::target::word RegExp_InstanceSize = 60; static constexpr dart::compiler::target::word Script_InstanceSize = 56; @@ -4093,7 +4093,7 @@ static constexpr dart::compiler::target::word OneByteString_InstanceSize = 16; static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48; static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16; static constexpr dart::compiler::target::word Pointer_InstanceSize = 24; -static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24; +static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40; static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32; static constexpr dart::compiler::target::word RegExp_InstanceSize = 120; static constexpr dart::compiler::target::word Script_InstanceSize = 96; @@ -4659,7 +4659,7 @@ static constexpr dart::compiler::target::word AOT_OneByteString_InstanceSize = static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 20; static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 8; static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 12; -static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 12; +static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 20; static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize = 16; static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 60; @@ -5233,7 +5233,7 @@ static constexpr dart::compiler::target::word AOT_OneByteString_InstanceSize = static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16; static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24; +static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120; @@ -5811,7 +5811,7 @@ static constexpr dart::compiler::target::word AOT_OneByteString_InstanceSize = static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16; static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24; +static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120; @@ -6377,7 +6377,7 @@ static constexpr dart::compiler::target::word AOT_OneByteString_InstanceSize = static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 20; static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 8; static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 12; -static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 12; +static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 20; static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize = 16; static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 60; @@ -6944,7 +6944,7 @@ static constexpr dart::compiler::target::word AOT_OneByteString_InstanceSize = static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16; static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24; +static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120; @@ -7515,7 +7515,7 @@ static constexpr dart::compiler::target::word AOT_OneByteString_InstanceSize = static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16; static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24; +static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120; diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc index a17966f66b6..63db37e039e 100644 --- a/runtime/vm/dart_entry.cc +++ b/runtime/vm/dart_entry.cc @@ -725,6 +725,31 @@ ObjectPtr DartLibraryCalls::LookupHandler(Dart_Port port_id) { return result.raw(); } +ObjectPtr DartLibraryCalls::LookupOpenPorts() { + Thread* thread = Thread::Current(); + Zone* zone = thread->zone(); + Function& function = Function::Handle( + zone, thread->isolate()->object_store()->lookup_open_ports()); + const int kTypeArgsLen = 0; + const int kNumArguments = 0; + if (function.IsNull()) { + Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary()); + ASSERT(!isolate_lib.IsNull()); + const String& class_name = String::Handle( + zone, isolate_lib.PrivateName(Symbols::_RawReceivePortImpl())); + const String& function_name = String::Handle( + zone, isolate_lib.PrivateName(Symbols::_lookupOpenPorts())); + function = Resolver::ResolveStatic(isolate_lib, class_name, function_name, + kTypeArgsLen, kNumArguments, + Object::empty_array()); + ASSERT(!function.IsNull()); + thread->isolate()->object_store()->set_lookup_open_ports(function); + } + const Object& result = Object::Handle( + zone, DartEntry::InvokeFunction(function, Object::empty_array())); + return result.raw(); +} + ObjectPtr DartLibraryCalls::HandleMessage(const Object& handler, const Instance& message) { Thread* thread = Thread::Current(); diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h index 2ebdbe8f38d..c85f683977e 100644 --- a/runtime/vm/dart_entry.h +++ b/runtime/vm/dart_entry.h @@ -282,6 +282,9 @@ class DartLibraryCalls : public AllStatic { // Returns the handler if one has been registered for this port id. static ObjectPtr LookupHandler(Dart_Port port_id); + // Returns a list of open ReceivePorts. + static ObjectPtr LookupOpenPorts(); + // Returns null on success, a RawError on failure. static ObjectPtr HandleMessage(const Object& handler, const Instance& dart_message); diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index 8b8bbc08e89..7a1c69e4e9b 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -2385,8 +2385,9 @@ static MessageHandler::MessageStatus RunIsolate(uword parameter) { args.SetAt(2, Instance::Handle(state->BuildArgs(thread))); args.SetAt(3, Instance::Handle(state->BuildMessage(thread))); args.SetAt(4, is_spawn_uri ? Bool::True() : Bool::False()); - args.SetAt(5, ReceivePort::Handle(ReceivePort::New( - isolate->main_port(), true /* control port */))); + args.SetAt(5, ReceivePort::Handle( + ReceivePort::New(isolate->main_port(), Symbols::Empty(), + true /* control port */))); args.SetAt(6, capabilities); const Library& lib = Library::Handle(Library::IsolateLibrary()); diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 330635d9b02..bc6666b763c 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -7,6 +7,7 @@ #include #include "include/dart_api.h" +#include "lib/stacktrace.h" #include "platform/assert.h" #include "platform/text_buffer.h" #include "platform/unaligned.h" @@ -23805,6 +23806,7 @@ const char* Capability::ToCString() const { } ReceivePortPtr ReceivePort::New(Dart_Port id, + const String& debug_name, bool is_control_port, Heap::Space space) { ASSERT(id != ILLEGAL_PORT); @@ -23812,6 +23814,8 @@ ReceivePortPtr ReceivePort::New(Dart_Port id, Zone* zone = thread->zone(); const SendPort& send_port = SendPort::Handle(zone, SendPort::New(id, thread->isolate()->origin_id())); + const StackTrace& allocation_location_ = + HasStack() ? GetCurrentStackTrace(0) : StackTrace::Handle(); ReceivePort& result = ReceivePort::Handle(zone); { @@ -23820,6 +23824,9 @@ ReceivePortPtr ReceivePort::New(Dart_Port id, NoSafepointScope no_safepoint; result ^= raw; result.StorePointer(&result.raw_ptr()->send_port_, send_port.raw()); + result.StorePointer(&result.raw_ptr()->debug_name_, debug_name.raw()); + result.StorePointer(&result.raw_ptr()->allocation_location_, + allocation_location_.raw()); } if (is_control_port) { PortMap::SetPortState(id, PortMap::kControlPort); diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 1a3cea05794..1bd2be8114b 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -10567,10 +10567,17 @@ class ReceivePort : public Instance { InstancePtr handler() const { return raw_ptr()->handler_; } void set_handler(const Instance& value) const; + StackTracePtr allocation_location() const { + return raw_ptr()->allocation_location_; + } + + StringPtr debug_name() const { return raw_ptr()->debug_name_; } + static intptr_t InstanceSize() { return RoundedAllocationSize(sizeof(ReceivePortLayout)); } static ReceivePortPtr New(Dart_Port id, + const String& debug_name, bool is_control_port, Heap::Space space = Heap::kNew); diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc index 0d6553eff79..acdaca6bd34 100644 --- a/runtime/vm/object_service.cc +++ b/runtime/vm/object_service.cc @@ -1452,7 +1452,15 @@ void Capability::PrintJSONImpl(JSONStream* stream, bool ref) const { } void ReceivePort::PrintJSONImpl(JSONStream* stream, bool ref) const { - Instance::PrintJSONImpl(stream, ref); + JSONObject obj(stream); + Instance::PrintSharedInstanceJSON(&obj, ref); + const StackTrace& allocation_location_ = + StackTrace::Handle(allocation_location()); + const String& debug_name_ = String::Handle(debug_name()); + obj.AddProperty("kind", "ReceivePort"); + obj.AddProperty64("portId", Id()); + obj.AddProperty("debugName", debug_name_.ToCString()); + obj.AddProperty("allocationLocation", allocation_location_); } void SendPort::PrintJSONImpl(JSONStream* stream, bool ref) const { diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h index dc51e07e0a1..829ae7ec80b 100644 --- a/runtime/vm/object_store.h +++ b/runtime/vm/object_store.h @@ -160,6 +160,7 @@ class ObjectPointerVisitor; RW(Instance, stack_overflow) \ RW(Instance, out_of_memory) \ RW(Function, lookup_port_handler) \ + RW(Function, lookup_open_ports) \ RW(Function, handle_message_function) \ RW(Function, growable_list_factory) \ RW(Function, simple_instance_of_function) \ diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 4a713b60614..a124ad57978 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -2726,7 +2726,9 @@ class ReceivePortLayout : public InstanceLayout { VISIT_FROM(ObjectPtr, send_port_) SendPortPtr send_port_; InstancePtr handler_; - VISIT_TO(ObjectPtr, handler_) + StringPtr debug_name_; + StackTracePtr allocation_location_; + VISIT_TO(ObjectPtr, allocation_location_) }; class TransferableTypedDataLayout : public InstanceLayout { diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc index 7276a2512b0..f5089d9f322 100644 --- a/runtime/vm/raw_object_fields.cc +++ b/runtime/vm/raw_object_fields.cc @@ -171,6 +171,8 @@ namespace dart { F(ExternalTypedData, length_) \ F(ReceivePort, send_port_) \ F(ReceivePort, handler_) \ + F(ReceivePort, debug_name_) \ + F(ReceivePort, allocation_location_) \ F(StackTrace, async_link_) \ F(StackTrace, code_array_) \ F(StackTrace, pc_offset_array_) \ diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index 23dfdde7021..d12772efd61 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -3142,6 +3142,30 @@ static bool GetInstances(Thread* thread, JSONStream* js) { return true; } +static const MethodParameter* get_ports_params[] = { + RUNNABLE_ISOLATE_PARAMETER, + NULL, +}; + +static bool GetPorts(Thread* thread, JSONStream* js) { + // Ensure the array and handles created below are promptly destroyed. + StackZone zone(thread); + HANDLESCOPE(thread); + const GrowableObjectArray& ports = GrowableObjectArray::Handle( + GrowableObjectArray::RawCast(DartLibraryCalls::LookupOpenPorts())); + JSONObject jsobj(js); + jsobj.AddProperty("type", "PortList"); + { + Instance& port = Instance::Handle(zone.GetZone()); + JSONArray arr(&jsobj, "ports"); + for (int i = 0; i < ports.Length(); ++i) { + port ^= ports.At(i); + arr.AddValue(port); + } + } + return true; +} + #if !defined(DART_PRECOMPILED_RUNTIME) static const char* const report_enum_names[] = { SourceReport::kCallSitesStr, @@ -4389,12 +4413,12 @@ static bool GetPersistentHandles(Thread* thread, JSONStream* js) { return true; } -static const MethodParameter* get_ports_params[] = { +static const MethodParameter* get_ports_private_params[] = { RUNNABLE_ISOLATE_PARAMETER, NULL, }; -static bool GetPorts(Thread* thread, JSONStream* js) { +static bool GetPortsPrivate(Thread* thread, JSONStream* js) { MessageHandler* message_handler = thread->isolate()->message_handler(); PortMap::PrintPortsForMessageHandler(message_handler, js); return true; @@ -5054,6 +5078,8 @@ static const ServiceMethodDescriptor service_methods_[] = { get_inbound_references_params }, { "getInstances", GetInstances, get_instances_params }, + { "getPorts", GetPorts, + get_ports_params }, { "getIsolate", GetIsolate, get_isolate_params }, { "_getIsolateObjectStore", GetIsolateObjectStore, @@ -5074,8 +5100,8 @@ static const ServiceMethodDescriptor service_methods_[] = { get_object_store_params }, { "_getPersistentHandles", GetPersistentHandles, get_persistent_handles_params, }, - { "_getPorts", GetPorts, - get_ports_params }, + { "_getPorts", GetPortsPrivate, + get_ports_private_params }, { "getProcessMemoryUsage", GetProcessMemoryUsage, get_process_memory_usage_params }, { "_getReachableSize", GetReachableSize, diff --git a/runtime/vm/service.h b/runtime/vm/service.h index bf1d99b0712..9d09af173b9 100644 --- a/runtime/vm/service.h +++ b/runtime/vm/service.h @@ -15,7 +15,7 @@ namespace dart { #define SERVICE_PROTOCOL_MAJOR_VERSION 3 -#define SERVICE_PROTOCOL_MINOR_VERSION 40 +#define SERVICE_PROTOCOL_MINOR_VERSION 41 class Array; class EmbedderServiceHandler; diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md index b8d09062787..6fe2fb88b2b 100644 --- a/runtime/vm/service/service.md +++ b/runtime/vm/service/service.md @@ -1,8 +1,8 @@ -# Dart VM Service Protocol 3.40 +# Dart VM Service Protocol 3.41 > Please post feedback to the [observatory-discuss group][discuss-list] -This document describes of _version 3.40_ of the Dart VM Service Protocol. This +This document describes of _version 3.41_ 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. @@ -47,6 +47,7 @@ The Service Protocol uses [JSON-RPC 2.0][]. - [getIsolateGroup](#getisolategroup) - [getMemoryUsage](#getmemoryusage) - [getObject](#getobject) + - [getPorts](#getports) - [getProcessMemoryUsage](#getprocessmemoryusage) - [getRetainingPath](#getretainingpath) - [getScripts](#getscripts) @@ -113,6 +114,7 @@ The Service Protocol uses [JSON-RPC 2.0][]. - [NativeFunction](#nativefunction) - [Null](#null) - [Object](#object) + - [PortList](#portlist) - [ReloadReport](#reloadreport) - [Response](#response) - [RetainingObject](#retainingobject) @@ -936,6 +938,17 @@ Int32List, Int64List, Flooat32List, Float64List, Inst32x3List, Float32x4List, and Float64x2List. These parameters are otherwise ignored. +### getPorts + +``` +PortList getPorts(string isolateId) +``` + +The _getPorts_ RPC is used to retrieve the list of `ReceivePort` instances for a +given isolate. + +See [PortList](#portlist). + ### getRetainingPath ``` @@ -2426,6 +2439,24 @@ class @Instance extends @Object { // Provided for instance kinds: // Closure @Context closureContext [optional]; + + // The port ID for a ReceivePort. + // + // Provided for instance kinds: + // ReceivePort + int portId [optional]; + + // The stack trace associated with the allocation of a ReceivePort. + // + // Provided for instance kinds: + // ReceivePort + @Instance allocationLocation [optional]; + + // A name associated with a ReceivePort used for debugging purposes. + // + // Provided for instance kinds: + // ReceivePort + string debugName [optional]; } ``` @@ -2446,6 +2477,7 @@ class Instance extends Object { // Double (suitable for passing to Double.parse()) // Int (suitable for passing to int.parse()) // String (value may be truncated) + // StackTrace string valueAsString [optional]; // The valueAsString for String references may be truncated. If so, @@ -2658,6 +2690,24 @@ class Instance extends Object { // BoundedType // TypeParameter @Instance bound [optional]; + + // The port ID for a ReceivePort. + // + // Provided for instance kinds: + // ReceivePort + int portId [optional]; + + // The stack trace associated with the allocation of a ReceivePort. + // + // Provided for instance kinds: + // ReceivePort + @Instance allocationLocation [optional]; + + // A name associated with a ReceivePort used for debugging purposes. + // + // Provided for instance kinds: + // ReceivePort + string debugName [optional]; } ``` @@ -2742,6 +2792,9 @@ enum InstanceKind { // An instance of the Dart class BoundedType. BoundedType, + + // An instance of the Dart class ReceivePort. + ReceivePort, } ``` @@ -3184,6 +3237,18 @@ class Object extends Response { An _Object_ is a persistent object that is owned by some isolate. +### PortList + +``` +class PortList extends Response { + @Instance[] ports; +} +``` + +A _PortList_ contains a list of ports associated with some isolate. + +See [getPort](#getPort). + ### ProfileFunction ``` @@ -3855,5 +3920,6 @@ version | comments 3.38 | Added `isSystemIsolate` property to `@Isolate` and `Isolate`, `isSystemIsolateGroup` property to `@IsolateGroup` and `IsolateGroup`, and properties `systemIsolates` and `systemIsolateGroups` to `VM`. 3.39 | Removed the following deprecated RPCs and objects: `getClientName`, `getWebSocketTarget`, `setClientName`, `requireResumeApproval`, `ClientName`, and `WebSocketTarget`. 3.40 | Added `IsolateFlag` object and `isolateFlags` property to `Isolate`. +3.41 | Added `PortList` object, `ReceivePort` `InstanceKind`, and `getPorts` RPC. [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index 40b953c06bb..d8f11c2f471 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -447,6 +447,7 @@ class ObjectPointerVisitor; V(_handleMessage, "_handleMessage") \ V(_instanceOf, "_instanceOf") \ V(_lookupHandler, "_lookupHandler") \ + V(_lookupOpenPorts, "_lookupOpenPorts") \ V(_name, "_name") \ V(_onData, "_onData") \ V(_rehashObjects, "_rehashObjects") \ diff --git a/sdk/lib/_internal/vm/lib/isolate_patch.dart b/sdk/lib/_internal/vm/lib/isolate_patch.dart index 91a567de2d5..97e90cef922 100644 --- a/sdk/lib/_internal/vm/lib/isolate_patch.dart +++ b/sdk/lib/_internal/vm/lib/isolate_patch.dart @@ -22,7 +22,8 @@ import "dart:_internal" show spawnFunction; @patch class ReceivePort { @patch - factory ReceivePort() => new _ReceivePortImpl(); + factory ReceivePort([String debugName = '']) => + new _ReceivePortImpl(debugName); @patch factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) { @@ -62,15 +63,16 @@ class RawReceivePort { * event is received. */ @patch - factory RawReceivePort([Function? handler]) { - _RawReceivePortImpl result = new _RawReceivePortImpl(); + factory RawReceivePort([Function? handler, String debugName = '']) { + _RawReceivePortImpl result = new _RawReceivePortImpl(debugName); result.handler = handler; return result; } } class _ReceivePortImpl extends Stream implements ReceivePort { - _ReceivePortImpl() : this.fromRawReceivePort(new RawReceivePort()); + _ReceivePortImpl([String debugName = '']) + : this.fromRawReceivePort(new RawReceivePort(null, debugName)); _ReceivePortImpl.fromRawReceivePort(this._rawPort) : _controller = new StreamController(sync: true) { @@ -128,11 +130,20 @@ Function _getIsolateScheduleImmediateClosure() { @pragma("vm:entry-point") class _RawReceivePortImpl implements RawReceivePort { - factory _RawReceivePortImpl() native "RawReceivePortImpl_factory"; + factory _RawReceivePortImpl(String debugName) { + final port = _RawReceivePortImpl._(debugName); + _portMap[port._get_id()] = { + 'port': port, + }; + return port; + } + + factory _RawReceivePortImpl._(String debugName) + native "RawReceivePortImpl_factory"; close() { // Close the port and remove it from the handler map. - _handlerMap.remove(this._closeInternal()); + _portMap.remove(this._closeInternal()); } SendPort get sendPort { @@ -155,10 +166,15 @@ class _RawReceivePortImpl implements RawReceivePort { // Called from the VM to retrieve the handler for a message. @pragma("vm:entry-point", "call") static _lookupHandler(int id) { - var result = _handlerMap[id]; + var result = _portMap[id]?['handler']; return result; } + @pragma("vm:entry-point", "call") + static _lookupOpenPorts() { + return _portMap.values.map((e) => e['port']).toList(); + } + // Called from the VM to dispatch to the handler. @pragma("vm:entry-point", "call") static void _handleMessage(Function handler, var message) { @@ -173,22 +189,16 @@ class _RawReceivePortImpl implements RawReceivePort { _closeInternal() native "RawReceivePortImpl_closeInternal"; void set handler(Function? value) { - _handlerMap[this._get_id()] = value; + final id = this._get_id(); + if (!_portMap.containsKey(id)) { + _portMap[id] = { + 'port': this, + }; + } + _portMap[id]!['handler'] = value; } - // TODO(iposva): Ideally keep this map in the VM. - // id to handler mapping. - static _initHandlerMap() { - // TODO(18511): Workaround bad CheckSmi hoisting. - var tempMap = new HashMap(); - // Collect feedback that not all keys are Smis. - tempMap["."] = 1; - tempMap["."] = 2; - - return new HashMap(); - } - - static final Map _handlerMap = _initHandlerMap(); + static final _portMap = >{}; } @pragma("vm:entry-point") diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart index 0c5747ea385..b7650dde074 100644 --- a/sdk/lib/isolate/isolate.dart +++ b/sdk/lib/isolate/isolate.dart @@ -671,9 +671,12 @@ abstract class ReceivePort implements Stream { * receive messages. See [Stream.asBroadcastStream] for transforming the port * to a broadcast stream. * + * The optional `debugName` parameter can be set to associate a name with + * this port that can be displayed in tooling. + * * A receive port is closed by canceling its subscription. */ - external factory ReceivePort(); + external factory ReceivePort([String debugName = '']); /** * Creates a [ReceivePort] from a [RawReceivePort]. @@ -718,8 +721,12 @@ abstract class RawReceivePort { * A [RawReceivePort] is low level and does not work with [Zone]s. It * can not be paused. The data-handler must be set before the first * event is received. + * + * The optional `debugName` parameter can be set to associate a name with + * this port that can be displayed in tooling. + * */ - external factory RawReceivePort([Function? handler]); + external factory RawReceivePort([Function? handler, String debugName = '']); /** * Sets the handler that is invoked for every incoming message.