[ 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 <rmacnak@google.com>
This commit is contained in:
Ben Konyi 2020-10-26 23:09:47 +00:00
parent 3a6cf0e6d4
commit 5bf9163e1b
35 changed files with 488 additions and 62 deletions

View file

@ -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

View file

@ -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.

View file

@ -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);

View file

@ -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

View file

@ -1 +1 @@
version=3.40
version=3.41

View file

@ -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<String, Function> _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<String, List<String>> _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<PortList> 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<PortList> getPorts(String isolateId) =>
_call('getPorts', {'isolateId': isolateId});
@override
Future<RetainingPath> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> json) =>
json == null ? null : PortList._fromJson(json);
List<InstanceRef> ports;
PortList({
@required this.ports,
});
PortList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
ports = List<InstanceRef>.from(
createServiceObject(json['ports'], const ['InstanceRef']) ?? []);
}
@override
Map<String, dynamic> toJson() {
var json = <String, dynamic>{};
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.
///

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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_

View file

@ -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) {

View file

@ -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);

View file

@ -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 = <IsolateTest>[
(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);

View file

@ -9,12 +9,12 @@ import 'test_helper.dart';
var tests = <VMTest>[
(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);
},
];

View file

@ -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) {

View file

@ -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);

View file

@ -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 = <IsolateTest>[
(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);

View file

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

View file

@ -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) \

View file

@ -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;

View file

@ -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();

View file

@ -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);

View file

@ -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());

View file

@ -7,6 +7,7 @@
#include <memory>
#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);

View file

@ -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);

View file

@ -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<intptr_t>(Id()));
obj.AddProperty("debugName", debug_name_.ToCString());
obj.AddProperty("allocationLocation", allocation_location_);
}
void SendPort::PrintJSONImpl(JSONStream* stream, bool ref) const {

View file

@ -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) \

View file

@ -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_)
};

View file

@ -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_) \

View file

@ -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,

View file

@ -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;

View file

@ -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

View file

@ -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") \

View file

@ -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 = <dynamic, Map<String, dynamic>>{};
}
@pragma("vm:entry-point")

View file

@ -671,9 +671,12 @@ abstract class ReceivePort implements Stream<dynamic> {
* 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.