From 5bf9163e1bbad42ca5cc66f4150055477a2fedff Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Mon, 26 Oct 2020 23:09:47 +0000 Subject: [PATCH] [ Service / dart:isolate ] Added getPorts RPC and 'debugName' optional parameter for ReceivePort and RawReceivePort This change collects additional information related to ReceivePort allocation locations and an optional debug name that will be displayed by tooling. ReceivePort is now a special InstanceKind and a ReceivePort @Instance will include the port ID, allocation stack trace, and debug name. Change-Id: I003cfff2b7649218e37d9b653c0e953df5d992e7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/167902 Reviewed-by: Ryan Macnak --- CHANGELOG.md | 10 +- pkg/vm_service/CHANGELOG.md | 7 ++ 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 | 2 + runtime/vm/raw_object_fields.cc | 1 + runtime/vm/service.cc | 33 ++++- runtime/vm/service.h | 2 +- runtime/vm/service/service.md | 70 ++++++++++- runtime/vm/symbols.h | 1 + sdk/lib/_internal/vm/lib/isolate_patch.dart | 55 +++++---- sdk/lib/isolate/isolate.dart | 11 +- 35 files changed, 488 insertions(+), 62 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 28b2ea504ab..c513296fa8c 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 ca07f4f1e1d..5dc6928d5a0 100644 --- a/pkg/vm_service/CHANGELOG.md +++ b/pkg/vm_service/CHANGELOG.md @@ -1,5 +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.0 - Added support for `dart:io` extensions version 1.4. - Update to version `3.40.0` of the spec. 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 690f8b62b53..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.0 +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 c2d8657fab4..4b2afb91a4b 100644 --- a/runtime/lib/stacktrace.cc +++ b/runtime/lib/stacktrace.cc @@ -224,4 +224,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 7215ef72d38..8352f386e38 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 046513de563..9b6ac2d9672 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 a9e7f65d26f..01514e3ca26 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -55,7 +55,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 bd58afd5f31..e2196c56fbc 100644 --- a/runtime/vm/compiler/runtime_offsets_extracted.h +++ b/runtime/vm/compiler/runtime_offsets_extracted.h @@ -504,7 +504,7 @@ static constexpr dart::compiler::target::word ParameterTypeCheck_InstanceSize = 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; @@ -1031,7 +1031,7 @@ static constexpr dart::compiler::target::word ParameterTypeCheck_InstanceSize = 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; @@ -1549,7 +1549,7 @@ static constexpr dart::compiler::target::word ParameterTypeCheck_InstanceSize = 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; @@ -2077,7 +2077,7 @@ static constexpr dart::compiler::target::word ParameterTypeCheck_InstanceSize = 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; @@ -2594,7 +2594,7 @@ static constexpr dart::compiler::target::word ParameterTypeCheck_InstanceSize = 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; @@ -3115,7 +3115,7 @@ static constexpr dart::compiler::target::word ParameterTypeCheck_InstanceSize = 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; @@ -3627,7 +3627,7 @@ static constexpr dart::compiler::target::word ParameterTypeCheck_InstanceSize = 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; @@ -4149,7 +4149,7 @@ static constexpr dart::compiler::target::word ParameterTypeCheck_InstanceSize = 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; @@ -4722,7 +4722,7 @@ static constexpr dart::compiler::target::word 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; @@ -5303,7 +5303,7 @@ static constexpr dart::compiler::target::word 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; @@ -5888,7 +5888,7 @@ static constexpr dart::compiler::target::word 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; @@ -6461,7 +6461,7 @@ static constexpr dart::compiler::target::word 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; @@ -7035,7 +7035,7 @@ static constexpr dart::compiler::target::word 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; @@ -7613,7 +7613,7 @@ static constexpr dart::compiler::target::word 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 aec36e8793d..89f06a9776e 100644 --- a/runtime/vm/dart_entry.cc +++ b/runtime/vm/dart_entry.cc @@ -750,6 +750,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 4f81b2817f2..1527c11d10c 100644 --- a/runtime/vm/dart_entry.h +++ b/runtime/vm/dart_entry.h @@ -284,6 +284,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 3f7e0023615..03f4c833d66 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -2395,8 +2395,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(), String::Handle(), + 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 de74fdbd3c7..089354bc864 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" @@ -24302,6 +24303,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); @@ -24309,6 +24311,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); { @@ -24317,6 +24321,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 71eeefd4379..627fe0e0f73 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -10959,10 +10959,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 fe34f62722a..3eb70c65151 100644 --- a/runtime/vm/object_service.cc +++ b/runtime/vm/object_service.cc @@ -1557,7 +1557,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.AddProperty("portId", static_cast(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 f436b1a8fbc..fe789afce48 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 00f48607987..21aae8b9de3 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -2788,6 +2788,8 @@ class ReceivePortLayout : public InstanceLayout { VISIT_FROM(ObjectPtr, send_port_) SendPortPtr send_port_; InstancePtr handler_; + StringPtr debug_name_; + StackTracePtr allocation_location_; VISIT_TO(ObjectPtr, handler_) }; diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc index 8b6b1848172..e3ad43de90a 100644 --- a/runtime/vm/raw_object_fields.cc +++ b/runtime/vm/raw_object_fields.cc @@ -182,6 +182,7 @@ namespace dart { F(ExternalTypedData, length_) \ F(ReceivePort, send_port_) \ F(ReceivePort, handler_) \ + 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 3a89d30a7c8..d144d8c16be 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -3146,6 +3146,29 @@ static bool GetInstances(Thread* thread, JSONStream* js) { return true; } +static const MethodParameter* get_ports_params[] = { + RUNNABLE_ISOLATE_PARAMETER, +}; + +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, @@ -4393,12 +4416,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; @@ -5058,6 +5081,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, @@ -5078,8 +5103,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 ba7cc2cd25f..55b1ba1786b 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -449,6 +449,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..8f8b02c15fb 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,21 @@ 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, + 'handler': null, + }; + 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 +167,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 +190,18 @@ 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, + 'handler': value, + }; + } else { + _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.