[vm, service] Fix discrepancy between VM generating kind _TypeParameters and service.md claiming the existence of kind TypeParameters.
Fix the service type `TypeParameters` to recognize it is a heap object. Exhaustively test that the service client libraries can handle inflating all types produced by the VM. Compare vm/cc/PrintJSON, which exhaustively tests the VM can generate any type. TEST=ci Bug: https://github.com/dart-lang/sdk/issues/52893 Change-Id: Id1f080656ef6e999e69f2ebb5b9961fa3b461e4a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/316862 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
Commit Queue
parent
c346b78f62
commit
5e49ea5ad8
@@ -1,3 +1,7 @@
|
||||
## 11.9.0
|
||||
- Update to version `4.12` of the spec.
|
||||
- Add `TypeParametersRef`; change supertype of `TypeParameters` to `Obj`.
|
||||
|
||||
## 11.8.0
|
||||
- Update to version `4.11` of the spec.
|
||||
- Add `isGetter` and `isSetter` properties to `FuncRef` and `Func`.
|
||||
|
||||
@@ -139,6 +139,7 @@ src/org/dartlang/vm/service/element/Timestamp.java
|
||||
src/org/dartlang/vm/service/element/TypeArguments.java
|
||||
src/org/dartlang/vm/service/element/TypeArgumentsRef.java
|
||||
src/org/dartlang/vm/service/element/TypeParameters.java
|
||||
src/org/dartlang/vm/service/element/TypeParametersRef.java
|
||||
src/org/dartlang/vm/service/element/UnresolvedSourceLocation.java
|
||||
src/org/dartlang/vm/service/element/UriList.java
|
||||
src/org/dartlang/vm/service/element/VM.java
|
||||
|
||||
@@ -1 +1 @@
|
||||
version=4.11
|
||||
version=4.12
|
||||
|
||||
@@ -28,7 +28,7 @@ export 'snapshot_graph.dart'
|
||||
HeapSnapshotObjectNoData,
|
||||
HeapSnapshotObjectNullData;
|
||||
|
||||
const String vmServiceVersion = '4.11.0';
|
||||
const String vmServiceVersion = '4.12.0';
|
||||
|
||||
/// @optional
|
||||
const String optional = 'optional';
|
||||
@@ -189,6 +189,7 @@ Map<String, Function> _typeFactories = {
|
||||
'Timestamp': Timestamp.parse,
|
||||
'@TypeArguments': TypeArgumentsRef.parse,
|
||||
'TypeArguments': TypeArguments.parse,
|
||||
'@TypeParameters': TypeParametersRef.parse,
|
||||
'TypeParameters': TypeParameters.parse,
|
||||
'UnresolvedSourceLocation': UnresolvedSourceLocation.parse,
|
||||
'UriList': UriList.parse,
|
||||
@@ -8826,14 +8827,49 @@ class TypeArguments extends Obj implements TypeArgumentsRef {
|
||||
String toString() => '[TypeArguments id: $id, name: $name, types: $types]';
|
||||
}
|
||||
|
||||
/// `TypeParametersRef` is a reference to a `TypeParameters` object.
|
||||
class TypeParametersRef extends ObjRef {
|
||||
static TypeParametersRef? parse(Map<String, dynamic>? json) =>
|
||||
json == null ? null : TypeParametersRef._fromJson(json);
|
||||
|
||||
TypeParametersRef({
|
||||
required String id,
|
||||
}) : super(
|
||||
id: id,
|
||||
);
|
||||
|
||||
TypeParametersRef._fromJson(Map<String, dynamic> json)
|
||||
: super._fromJson(json);
|
||||
|
||||
@override
|
||||
String get type => '@TypeParameters';
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = super.toJson();
|
||||
json['type'] = type;
|
||||
return json;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
other is TypeParametersRef && id == other.id;
|
||||
|
||||
@override
|
||||
String toString() => '[TypeParametersRef id: $id]';
|
||||
}
|
||||
|
||||
/// A `TypeParameters` object represents the type argument vector for some
|
||||
/// uninstantiated generic type.
|
||||
class TypeParameters {
|
||||
class TypeParameters extends Obj implements TypeParametersRef {
|
||||
static TypeParameters? parse(Map<String, dynamic>? json) =>
|
||||
json == null ? null : TypeParameters._fromJson(json);
|
||||
|
||||
/// The names of the type parameters.
|
||||
List<String>? names;
|
||||
InstanceRef? names;
|
||||
|
||||
/// The bounds set on each type parameter.
|
||||
TypeArgumentsRef? bounds;
|
||||
@@ -8845,29 +8881,44 @@ class TypeParameters {
|
||||
this.names,
|
||||
this.bounds,
|
||||
this.defaults,
|
||||
});
|
||||
required String id,
|
||||
}) : super(
|
||||
id: id,
|
||||
);
|
||||
|
||||
TypeParameters._fromJson(Map<String, dynamic> json) {
|
||||
names = List<String>.from(json['names']);
|
||||
TypeParameters._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
|
||||
names = createServiceObject(json['names'], const ['InstanceRef'])
|
||||
as InstanceRef?;
|
||||
bounds = createServiceObject(json['bounds'], const ['TypeArgumentsRef'])
|
||||
as TypeArgumentsRef?;
|
||||
defaults = createServiceObject(json['defaults'], const ['TypeArgumentsRef'])
|
||||
as TypeArgumentsRef?;
|
||||
}
|
||||
|
||||
@override
|
||||
String get type => 'TypeParameters';
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
final json = super.toJson();
|
||||
json['type'] = type;
|
||||
json.addAll({
|
||||
'names': names?.map((f) => f).toList(),
|
||||
'names': names?.toJson(),
|
||||
'bounds': bounds?.toJson(),
|
||||
'defaults': defaults?.toJson(),
|
||||
});
|
||||
return json;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => other is TypeParameters && id == other.id;
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'[TypeParameters names: $names, bounds: $bounds, defaults: $defaults]';
|
||||
'[TypeParameters id: $id, names: $names, bounds: $bounds, defaults: $defaults]';
|
||||
}
|
||||
|
||||
/// The `UnresolvedSourceLocation` class is used to refer to an unresolved
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: vm_service
|
||||
version: 11.8.0
|
||||
version: 11.9.0
|
||||
description: >-
|
||||
A library to communicate with a service implementing the Dart VM
|
||||
service protocol.
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2023, 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.
|
||||
|
||||
// See https://github.com/dart-lang/sdk/issues/52893
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
var tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
var profile = await service.getAllocationProfile(isolateRef.id!);
|
||||
for (var entry in profile.members!) {
|
||||
if (entry.instancesCurrent == 0) continue;
|
||||
|
||||
var classRef = entry.classRef!;
|
||||
print(classRef);
|
||||
var instanceSet =
|
||||
await service.getInstances(isolateRef.id!, classRef.id!, 10);
|
||||
for (var instance in instanceSet.instances!) {
|
||||
await service.getObject(isolateRef.id!, instance.id!);
|
||||
}
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
main(args) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'fetch_all_types_test.dart',
|
||||
);
|
||||
@@ -149,6 +149,16 @@ class InstanceRefElement extends CustomElement implements Renderable {
|
||||
new SpanElement()..text = ' (${_instance.pattern!.valueAsString})'
|
||||
]
|
||||
];
|
||||
case M.InstanceKind.userTag:
|
||||
return [
|
||||
new AnchorElement(href: Uris.inspect(_isolate, object: _instance))
|
||||
..children = <Element>[
|
||||
new SpanElement()
|
||||
..classes = ['emphasize']
|
||||
..text = _instance.clazz!.name,
|
||||
new SpanElement()..text = ' (${_instance.name})'
|
||||
]
|
||||
];
|
||||
case M.InstanceKind.stackTrace:
|
||||
return [
|
||||
new AnchorElement(href: Uris.inspect(_isolate, object: _instance))
|
||||
|
||||
@@ -139,6 +139,9 @@ enum InstanceKind {
|
||||
|
||||
/// An instance of WeakReference
|
||||
weakReference,
|
||||
|
||||
/// An instance of UserTag
|
||||
userTag,
|
||||
}
|
||||
|
||||
bool isTypedData(InstanceKind? kind) {
|
||||
|
||||
@@ -266,6 +266,24 @@ abstract class ServiceObject implements M.ObjectRef {
|
||||
case 'UnlinkedCall':
|
||||
obj = new UnlinkedCall._empty(owner);
|
||||
break;
|
||||
case 'ClosureData':
|
||||
case 'CodeSourceMap':
|
||||
case 'ContextScope':
|
||||
case 'ExceptionHandlers':
|
||||
case 'FfiTrampolineData':
|
||||
case 'Instructions':
|
||||
case 'InstructionsSection':
|
||||
case 'KernelProgramInfo':
|
||||
case 'LibraryPrefix':
|
||||
case 'Namespace':
|
||||
case 'PatchClass':
|
||||
case 'WeakArray':
|
||||
obj = new GenericHeapObject._empty(owner);
|
||||
break;
|
||||
default:
|
||||
print('Unknown vmType: $vmType');
|
||||
obj = new GenericHeapObject._empty(owner);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'Event':
|
||||
@@ -286,6 +304,9 @@ abstract class ServiceObject implements M.ObjectRef {
|
||||
case 'TypeArguments':
|
||||
obj = new TypeArguments._empty(owner);
|
||||
break;
|
||||
case 'TypeParameters':
|
||||
obj = new GenericHeapObject._empty(owner);
|
||||
break;
|
||||
case 'Instance':
|
||||
obj = new Instance._empty(owner);
|
||||
break;
|
||||
@@ -427,6 +448,15 @@ abstract class HeapObject extends ServiceObject implements M.Object {
|
||||
}
|
||||
}
|
||||
|
||||
class GenericHeapObject extends HeapObject {
|
||||
GenericHeapObject._empty(ServiceObjectOwner? owner) : super._empty(owner);
|
||||
|
||||
void _update(Map map, bool mapIsRef) {
|
||||
_upgradeCollection(map, isolate);
|
||||
super._update(map, mapIsRef);
|
||||
}
|
||||
}
|
||||
|
||||
class RetainingObject implements M.RetainingObject {
|
||||
int get retainedSize => object.retainedSize!;
|
||||
final HeapObject object;
|
||||
@@ -2788,6 +2818,8 @@ M.InstanceKind stringToInstanceKind(String s) {
|
||||
return M.InstanceKind.finalizer;
|
||||
case 'WeakReference':
|
||||
return M.InstanceKind.weakReference;
|
||||
case 'UserTag':
|
||||
return M.InstanceKind.userTag;
|
||||
}
|
||||
var message = 'Unrecognized instance kind: $s';
|
||||
Logger.root.severe(message);
|
||||
@@ -2885,6 +2917,7 @@ class Instance extends HeapObject implements M.Instance {
|
||||
bool get isRegExp => kind == M.InstanceKind.regExp;
|
||||
bool get isMirrorReference => kind == M.InstanceKind.mirrorReference;
|
||||
bool get isWeakProperty => kind == M.InstanceKind.weakProperty;
|
||||
bool get isUserTag => kind == M.InstanceKind.userTag;
|
||||
bool get isClosure => kind == M.InstanceKind.closure;
|
||||
bool get isStackTrace => kind == M.InstanceKind.stackTrace;
|
||||
bool get isStackOverflowError {
|
||||
@@ -2926,6 +2959,9 @@ class Instance extends HeapObject implements M.Instance {
|
||||
valueAsStringIsTruncated = map['valueAsStringIsTruncated'] == true;
|
||||
closureFunction = map['closureFunction'];
|
||||
name = map['name']?.toString();
|
||||
if (map['label'] != null) {
|
||||
name = map['label'];
|
||||
}
|
||||
length = map['length'];
|
||||
pattern = map['pattern'];
|
||||
typeClass = map['typeClass'];
|
||||
@@ -3040,7 +3076,9 @@ class Instance extends HeapObject implements M.Instance {
|
||||
} else {
|
||||
typedElements = null;
|
||||
}
|
||||
parameterizedClass = map['parameterizedClass'];
|
||||
if (map['parameterizedClass'] is Class) {
|
||||
parameterizedClass = map['parameterizedClass'];
|
||||
}
|
||||
typeArguments = map['typeArguments'];
|
||||
parameterIndex = map['parameterIndex'];
|
||||
bound = map['bound'];
|
||||
@@ -3623,7 +3661,9 @@ class Script extends HeapObject implements M.Script {
|
||||
loadTime = new DateTime.fromMillisecondsSinceEpoch(loadTimeMillis);
|
||||
lineOffset = map['lineOffset'];
|
||||
columnOffset = map['columnOffset'];
|
||||
_parseTokenPosTable(map['tokenPosTable']);
|
||||
if (map['tokenPosTable'] != null) {
|
||||
_parseTokenPosTable(map['tokenPosTable']);
|
||||
}
|
||||
source = map['source'];
|
||||
_processSource(map['source']);
|
||||
library = map['library'];
|
||||
@@ -3875,21 +3915,18 @@ class PcDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
class PcDescriptors extends ServiceObject implements M.PcDescriptorsRef {
|
||||
Class? clazz;
|
||||
int? size;
|
||||
class PcDescriptors extends HeapObject implements M.PcDescriptorsRef {
|
||||
bool get immutable => true;
|
||||
final List<PcDescriptor> descriptors = <PcDescriptor>[];
|
||||
|
||||
PcDescriptors._empty(ServiceObjectOwner? owner) : super._empty(owner) {}
|
||||
|
||||
void _update(Map m, bool mapIsRef) {
|
||||
_upgradeCollection(m, isolate);
|
||||
super._update(m, mapIsRef);
|
||||
if (mapIsRef) {
|
||||
return;
|
||||
}
|
||||
_upgradeCollection(m, isolate);
|
||||
clazz = m['class'];
|
||||
size = m['size'];
|
||||
descriptors.clear();
|
||||
for (var descriptor in m['members']) {
|
||||
var pcOffset = int.parse(descriptor['pcOffset'], radix: 16);
|
||||
@@ -4435,7 +4472,12 @@ class Code extends HeapObject implements M.Code {
|
||||
var tryIndex = descriptor['tryIndex'];
|
||||
var kind = descriptor['kind'].trim();
|
||||
|
||||
var instruction = instructionsByAddressOffset![address - startAddress];
|
||||
CodeInstruction? instruction = null;
|
||||
int addressOffset = address - startAddress;
|
||||
if ((addressOffset >= 0) &&
|
||||
(addressOffset < instructionsByAddressOffset!.length)) {
|
||||
instruction = instructionsByAddressOffset![addressOffset];
|
||||
}
|
||||
if (instruction != null) {
|
||||
instruction.descriptors
|
||||
.add(new PcDescriptor(pcOffset, deoptId, tokenPos, tryIndex, kind));
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2023, 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.
|
||||
|
||||
// See https://github.com/dart-lang/sdk/issues/52893
|
||||
|
||||
import 'package:observatory/service_io.dart';
|
||||
import 'test_helper.dart';
|
||||
|
||||
var tests = <IsolateTest>[
|
||||
(Isolate isolate) async {
|
||||
dynamic profile = await isolate.invokeRpc('getAllocationProfile', {});
|
||||
for (var entry in profile["members"]) {
|
||||
if (entry["instancesCurrent"] == 0) continue;
|
||||
|
||||
Class cls = entry["class"];
|
||||
print(cls);
|
||||
dynamic rawInstanceSet = await isolate.invokeRpcNoUpgrade(
|
||||
'getInstances', {'objectId': cls.id, 'limit': 10});
|
||||
dynamic instanceSet = await isolate.getInstances(cls, 10);
|
||||
for (var instance in instanceSet.instances) {
|
||||
await instance.load();
|
||||
}
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
main(args) async => runIsolateTests(args, tests);
|
||||
@@ -12,7 +12,7 @@ var tests = <VMTest>[
|
||||
final result = await vm.invokeRpcNoUpgrade('getVersion', {});
|
||||
expect(result['type'], 'Version');
|
||||
expect(result['major'], 4);
|
||||
expect(result['minor'], 11);
|
||||
expect(result['minor'], 12);
|
||||
expect(result['_privateMajor'], 0);
|
||||
expect(result['_privateMinor'], 0);
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@ var tests = <VMTest>[
|
||||
final result = await vm.invokeRpcNoUpgrade('getVersion', {});
|
||||
expect(result['type'], equals('Version'));
|
||||
expect(result['major'], equals(4));
|
||||
expect(result['minor'], equals(11));
|
||||
expect(result['minor'], equals(12));
|
||||
expect(result['_privateMajor'], equals(0));
|
||||
expect(result['_privateMinor'], equals(0));
|
||||
},
|
||||
|
||||
@@ -203,10 +203,12 @@ void Class::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const {
|
||||
}
|
||||
|
||||
void TypeParameters::PrintJSONImpl(JSONStream* stream, bool ref) const {
|
||||
// Consider making this type public if we decide to expose TypeParameters
|
||||
// through the protocol.
|
||||
JSONObject jsobj(stream);
|
||||
jsobj.AddProperty("kind", "_TypeParameters");
|
||||
AddCommonObjectProperties(&jsobj, "TypeParameters", ref);
|
||||
jsobj.AddServiceId(*this);
|
||||
if (ref) {
|
||||
return;
|
||||
}
|
||||
jsobj.AddProperty("flags", Array::Handle(flags()));
|
||||
jsobj.AddProperty("names", Array::Handle(names()));
|
||||
jsobj.AddProperty("bounds", TypeArguments::Handle(bounds()));
|
||||
@@ -736,12 +738,7 @@ void KernelProgramInfo::PrintImplementationFieldsImpl(
|
||||
const JSONArray& jsarr_fields) const {}
|
||||
|
||||
void Instructions::PrintJSONImpl(JSONStream* stream, bool ref) const {
|
||||
JSONObject jsobj(stream);
|
||||
AddCommonObjectProperties(&jsobj, "Object", ref);
|
||||
jsobj.AddServiceId(*this);
|
||||
if (ref) {
|
||||
return;
|
||||
}
|
||||
Object::PrintJSONImpl(stream, ref);
|
||||
}
|
||||
|
||||
void Instructions::PrintImplementationFieldsImpl(
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
namespace dart {
|
||||
|
||||
#define SERVICE_PROTOCOL_MAJOR_VERSION 4
|
||||
#define SERVICE_PROTOCOL_MINOR_VERSION 11
|
||||
#define SERVICE_PROTOCOL_MINOR_VERSION 12
|
||||
|
||||
class Array;
|
||||
class EmbedderServiceHandler;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Dart VM Service Protocol 4.11
|
||||
# Dart VM Service Protocol 4.12
|
||||
|
||||
> Please post feedback to the [observatory-discuss group][discuss-list]
|
||||
|
||||
This document describes of _version 4.11_ of the Dart VM Service Protocol. This
|
||||
This document describes of _version 4.12_ 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.
|
||||
@@ -4508,9 +4508,16 @@ instantiated generic type.
|
||||
### TypeParameters
|
||||
|
||||
```
|
||||
class TypeParameters {
|
||||
class @TypeParameters extends @Object {
|
||||
}
|
||||
```
|
||||
|
||||
_@TypeParameters_ is a reference to a _TypeParameters_ object.
|
||||
|
||||
```
|
||||
class TypeParameters extends Object {
|
||||
// The names of the type parameters.
|
||||
string[] names;
|
||||
@Instance names;
|
||||
|
||||
// The bounds set on each type parameter.
|
||||
@TypeArguments bounds;
|
||||
@@ -4719,5 +4726,6 @@ version | comments
|
||||
4.9 | Added `isolateGroup` property to `Event`.
|
||||
4.10 | Deprecated `isSyntheticAsyncContinuation` on `Breakpoint`.
|
||||
4.11 | Added `isGetter` and `isSetter` properties to `@Function` and `Function`.
|
||||
4.12 | Added `@TypeParameters` and changed `TypeParameters` to extend `Object`.
|
||||
|
||||
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
|
||||
|
||||
Reference in New Issue
Block a user