Revert "[3.0 alpha][VM/Service] Update VM Service spec to v4.0"

This reverts commit c21f7c847c.

Reason for revert: Appears to cause issues when flutter app is launched with VSCode or Android Studio, please see https://github.com/flutter/flutter/issues/117526

Original change's description:
> [3.0 alpha][VM/Service] Update VM Service spec to v4.0
>
> This CL updates the VM Service spec to version 4.0 in order to add
> support for records. Some deprecated procedures and properties will also
> be removed in v4.0.
>
> As described in service.md's changelog, this CL:
> Adds `Record` and `RecordType` `InstanceKind`s, adds a deprecation
> notice to the `decl` property of `BoundField`, adds `name` property to
> `BoundField`, adds a deprecation notice to the `parentListIndex`
> property of `InboundReference`, changes the type of the `parentField`
> property of `InboundReference` from `@Field` to `@Field|string|int`,
> adds a deprecation notice to the `parentListIndex` property of
> `RetainingObject`, changes the type of the `parentField` property of
> `RetainingObject` from `string` to `string|int`, removes the deprecated
> `setExceptionPauseMode` procedure, removes the deprecated `timeSpan`
> property from `CpuSamples`, and removes the deprecated `timeSpan`
> property from `CpuSamplesEvent.
>
> TEST=CI
>
> Issue: https://github.com/dart-lang/sdk/issues/49725
> Change-Id: I7bf61c1ba11a0c7fd95a10c9c02c14282062b802
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/268521
> Commit-Queue: Derek Xu <derekx@google.com>
> Reviewed-by: Ben Konyi <bkonyi@google.com>

# Not skipping CQ checks because original CL landed > 1 day ago.

Issue: https://github.com/dart-lang/sdk/issues/49725
Change-Id: Ieb2a09653192e165ea8cf68965647e346e3a318b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/277181
Reviewed-by: Derek Xu <derekx@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Auto-Submit: Siva Annamalai <asiva@google.com>
Commit-Queue: Siva Annamalai <asiva@google.com>
This commit is contained in:
Siva Annamalai 2022-12-22 20:19:00 +00:00 committed by Commit Queue
parent 59ec6a3d46
commit dcaf392d34
20 changed files with 295 additions and 133 deletions

View file

@ -200,6 +200,7 @@ class CachedCpuSamples extends CpuSamples {
required int? samplePeriod, required int? samplePeriod,
required int? maxStackDepth, required int? maxStackDepth,
required int? sampleCount, required int? sampleCount,
required int? timeSpan,
required int? timeOriginMicros, required int? timeOriginMicros,
required int? timeExtentMicros, required int? timeExtentMicros,
required int? pid, required int? pid,
@ -209,6 +210,7 @@ class CachedCpuSamples extends CpuSamples {
samplePeriod: samplePeriod, samplePeriod: samplePeriod,
maxStackDepth: maxStackDepth, maxStackDepth: maxStackDepth,
sampleCount: sampleCount, sampleCount: sampleCount,
timeSpan: timeSpan,
timeOriginMicros: timeOriginMicros, timeOriginMicros: timeOriginMicros,
timeExtentMicros: timeExtentMicros, timeExtentMicros: timeExtentMicros,
pid: pid, pid: pid,
@ -223,6 +225,7 @@ class CachedCpuSamples extends CpuSamples {
samplePeriod: json['samplePeriod'] ?? -1, samplePeriod: json['samplePeriod'] ?? -1,
maxStackDepth: json['maxStackDepth'] ?? -1, maxStackDepth: json['maxStackDepth'] ?? -1,
sampleCount: json['sampleCount'] ?? -1, sampleCount: json['sampleCount'] ?? -1,
timeSpan: json['timeSpan'] ?? -1,
timeOriginMicros: json['timeOriginMicros'] ?? -1, timeOriginMicros: json['timeOriginMicros'] ?? -1,
timeExtentMicros: json['timeExtentMicros'] ?? -1, timeExtentMicros: json['timeExtentMicros'] ?? -1,
pid: json['pid'] ?? -1, pid: json['pid'] ?? -1,

View file

@ -34,6 +34,7 @@ src/org/dartlang/vm/service/consumer/ReloadSourcesConsumer.java
src/org/dartlang/vm/service/consumer/RemoveBreakpointConsumer.java src/org/dartlang/vm/service/consumer/RemoveBreakpointConsumer.java
src/org/dartlang/vm/service/consumer/RequestHeapSnapshotConsumer.java src/org/dartlang/vm/service/consumer/RequestHeapSnapshotConsumer.java
src/org/dartlang/vm/service/consumer/ResumeConsumer.java src/org/dartlang/vm/service/consumer/ResumeConsumer.java
src/org/dartlang/vm/service/consumer/SetExceptionPauseModeConsumer.java
src/org/dartlang/vm/service/consumer/SetFlagConsumer.java src/org/dartlang/vm/service/consumer/SetFlagConsumer.java
src/org/dartlang/vm/service/consumer/SetIsolatePauseModeConsumer.java src/org/dartlang/vm/service/consumer/SetIsolatePauseModeConsumer.java
src/org/dartlang/vm/service/consumer/SetLibraryDebuggableConsumer.java src/org/dartlang/vm/service/consumer/SetLibraryDebuggableConsumer.java

View file

@ -587,17 +587,17 @@ public class VmServiceTest {
private static void vmPauseOnException(IsolateRef isolate, ExceptionPauseMode mode) { private static void vmPauseOnException(IsolateRef isolate, ExceptionPauseMode mode) {
System.out.println("Request pause on exception: " + mode); System.out.println("Request pause on exception: " + mode);
final OpLatch latch = new OpLatch(); final OpLatch latch = new OpLatch();
vmService.setIsolatePauseMode(isolate.getId(), mode, new SuccessConsumer() { vmService.setExceptionPauseMode(isolate.getId(), mode, new SuccessConsumer() {
@Override @Override
public void onError(RPCError error) { public void onError(RPCError error) {
showRPCError(error); showRPCError(error);
} }
@Override @Override
public void received(Success response) { public void received(Success response) {
System.out.println("Successfully set pause on exception"); System.out.println("Successfully set pause on exception");
latch.opComplete(); latch.opComplete();
} }
}); });
latch.waitAndAssertOpComplete(); latch.waitAndAssertOpComplete();
} }

View file

@ -1 +1 @@
version=4.0 version=3.62

View file

@ -26,7 +26,7 @@ export 'snapshot_graph.dart'
HeapSnapshotObjectNoData, HeapSnapshotObjectNoData,
HeapSnapshotObjectNullData; HeapSnapshotObjectNullData;
const String vmServiceVersion = '4.0.0'; const String vmServiceVersion = '3.62.0';
/// @optional /// @optional
const String optional = 'optional'; const String optional = 'optional';
@ -236,6 +236,7 @@ Map<String, List<String>> _methodReturnTypes = {
'requestHeapSnapshot': const ['Success'], 'requestHeapSnapshot': const ['Success'],
'resume': const ['Success'], 'resume': const ['Success'],
'setBreakpointState': const ['Breakpoint'], 'setBreakpointState': const ['Breakpoint'],
'setExceptionPauseMode': const ['Success'],
'setIsolatePauseMode': const ['Success'], 'setIsolatePauseMode': const ['Success'],
'setFlag': const ['Success', 'Error'], 'setFlag': const ['Success', 'Error'],
'setLibraryDebuggable': const ['Success'], 'setLibraryDebuggable': const ['Success'],
@ -1076,12 +1077,33 @@ abstract class VmServiceInterface {
Future<Breakpoint> setBreakpointState( Future<Breakpoint> setBreakpointState(
String isolateId, String breakpointId, bool enable); String isolateId, String breakpointId, bool enable);
/// The `setExceptionPauseMode` RPC is used to control if an isolate pauses
/// when an exception is thrown.
///
/// mode | meaning
/// ---- | -------
/// None | Do not pause isolate on thrown exceptions
/// Unhandled | Pause isolate on unhandled exceptions
/// All | Pause isolate on all thrown exceptions
///
/// If `isolateId` refers to an isolate which has exited, then the `Collected`
/// [Sentinel] is returned.
///
/// This method will throw a [SentinelException] in the case a [Sentinel] is
/// returned.
@Deprecated('Use setIsolatePauseMode instead')
Future<Success> setExceptionPauseMode(
String isolateId, /*ExceptionPauseMode*/ String mode);
/// The `setIsolatePauseMode` RPC is used to control if or when an isolate /// The `setIsolatePauseMode` RPC is used to control if or when an isolate
/// will pause due to a change in execution state. /// will pause due to a change in execution state.
/// ///
/// The `shouldPauseOnExit` parameter specify whether the target isolate /// The `shouldPauseOnExit` parameter specify whether the target isolate
/// should pause on exit. /// should pause on exit.
/// ///
/// The `setExceptionPauseMode` RPC is used to control if an isolate pauses
/// when an exception is thrown.
///
/// mode | meaning /// mode | meaning
/// ---- | ------- /// ---- | -------
/// None | Do not pause isolate on thrown exceptions /// None | Do not pause isolate on thrown exceptions
@ -1576,6 +1598,13 @@ class VmServerConnection {
params['enable'], params['enable'],
); );
break; break;
case 'setExceptionPauseMode':
// ignore: deprecated_member_use_from_same_package
response = await _serviceImplementation.setExceptionPauseMode(
params!['isolateId'],
params['mode'],
);
break;
case 'setIsolatePauseMode': case 'setIsolatePauseMode':
response = await _serviceImplementation.setIsolatePauseMode( response = await _serviceImplementation.setIsolatePauseMode(
params!['isolateId'], params!['isolateId'],
@ -2120,6 +2149,12 @@ class VmService implements VmServiceInterface {
'enable': enable 'enable': enable
}); });
@Deprecated('Use setIsolatePauseMode instead')
@override
Future<Success> setExceptionPauseMode(
String isolateId, /*ExceptionPauseMode*/ String mode) =>
_call('setExceptionPauseMode', {'isolateId': isolateId, 'mode': mode});
@override @override
Future<Success> setIsolatePauseMode(String isolateId, Future<Success> setIsolatePauseMode(String isolateId,
{/*ExceptionPauseMode*/ String? exceptionPauseMode, {/*ExceptionPauseMode*/ String? exceptionPauseMode,
@ -2682,9 +2717,6 @@ class InstanceKind {
static const String kFloat32x4List = 'Float32x4List'; static const String kFloat32x4List = 'Float32x4List';
static const String kFloat64x2List = 'Float64x2List'; static const String kFloat64x2List = 'Float64x2List';
/// An instance of the Dart class Record.
static const String kRecord = 'Record';
/// An instance of the Dart class StackTrace. /// An instance of the Dart class StackTrace.
static const String kStackTrace = 'StackTrace'; static const String kStackTrace = 'StackTrace';
@ -2716,9 +2748,6 @@ class InstanceKind {
/// An instance of the Dart class FunctionType. /// An instance of the Dart class FunctionType.
static const String kFunctionType = 'FunctionType'; static const String kFunctionType = 'FunctionType';
/// An instance of the Dart class RecordType.
static const String kRecordType = 'RecordType';
/// An instance of the Dart class BoundedType. /// An instance of the Dart class BoundedType.
static const String kBoundedType = 'BoundedType'; static const String kBoundedType = 'BoundedType';
@ -2878,29 +2907,18 @@ class BoundField {
static BoundField? parse(Map<String, dynamic>? json) => static BoundField? parse(Map<String, dynamic>? json) =>
json == null ? null : BoundField._fromJson(json); json == null ? null : BoundField._fromJson(json);
/// Provided for fields of instances that are NOT of the following instance
/// kinds:
/// - Record
///
/// Note: this property is deprecated and will be replaced by `name`.
FieldRef? decl; FieldRef? decl;
/// [name] can be one of [String] or [int].
dynamic name;
/// [value] can be one of [InstanceRef] or [Sentinel]. /// [value] can be one of [InstanceRef] or [Sentinel].
dynamic value; dynamic value;
BoundField({ BoundField({
this.decl, this.decl,
this.name,
this.value, this.value,
}); });
BoundField._fromJson(Map<String, dynamic> json) { BoundField._fromJson(Map<String, dynamic> json) {
decl = createServiceObject(json['decl'], const ['FieldRef']) as FieldRef?; decl = createServiceObject(json['decl'], const ['FieldRef']) as FieldRef?;
name =
createServiceObject(json['name'], const ['String', 'int']) as dynamic;
value = value =
createServiceObject(json['value'], const ['InstanceRef', 'Sentinel']) createServiceObject(json['value'], const ['InstanceRef', 'Sentinel'])
as dynamic; as dynamic;
@ -2910,14 +2928,12 @@ class BoundField {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
json.addAll({ json.addAll({
'decl': decl?.toJson(), 'decl': decl?.toJson(),
'name': name?.toJson(),
'value': value?.toJson(), 'value': value?.toJson(),
}); });
return json; return json;
} }
String toString() => String toString() => '[BoundField decl: ${decl}, value: ${value}]';
'[BoundField decl: ${decl}, name: ${name}, value: ${value}]';
} }
/// A `BoundVariable` represents a local variable bound to a particular value in /// A `BoundVariable` represents a local variable bound to a particular value in
@ -3610,6 +3626,13 @@ class CpuSamples extends Response {
/// The number of samples returned. /// The number of samples returned.
int? sampleCount; int? sampleCount;
/// The timespan the set of returned samples covers, in microseconds
/// (deprecated).
///
/// Note: this property is deprecated and will always return -1. Use
/// `timeExtentMicros` instead.
int? timeSpan;
/// The start of the period of time in which the returned samples were /// The start of the period of time in which the returned samples were
/// collected. /// collected.
int? timeOriginMicros; int? timeOriginMicros;
@ -3633,6 +3656,7 @@ class CpuSamples extends Response {
this.samplePeriod, this.samplePeriod,
this.maxStackDepth, this.maxStackDepth,
this.sampleCount, this.sampleCount,
this.timeSpan,
this.timeOriginMicros, this.timeOriginMicros,
this.timeExtentMicros, this.timeExtentMicros,
this.pid, this.pid,
@ -3644,6 +3668,7 @@ class CpuSamples extends Response {
samplePeriod = json['samplePeriod'] ?? -1; samplePeriod = json['samplePeriod'] ?? -1;
maxStackDepth = json['maxStackDepth'] ?? -1; maxStackDepth = json['maxStackDepth'] ?? -1;
sampleCount = json['sampleCount'] ?? -1; sampleCount = json['sampleCount'] ?? -1;
timeSpan = json['timeSpan'] ?? -1;
timeOriginMicros = json['timeOriginMicros'] ?? -1; timeOriginMicros = json['timeOriginMicros'] ?? -1;
timeExtentMicros = json['timeExtentMicros'] ?? -1; timeExtentMicros = json['timeExtentMicros'] ?? -1;
pid = json['pid'] ?? -1; pid = json['pid'] ?? -1;
@ -3667,6 +3692,7 @@ class CpuSamples extends Response {
'samplePeriod': samplePeriod ?? -1, 'samplePeriod': samplePeriod ?? -1,
'maxStackDepth': maxStackDepth ?? -1, 'maxStackDepth': maxStackDepth ?? -1,
'sampleCount': sampleCount ?? -1, 'sampleCount': sampleCount ?? -1,
'timeSpan': timeSpan ?? -1,
'timeOriginMicros': timeOriginMicros ?? -1, 'timeOriginMicros': timeOriginMicros ?? -1,
'timeExtentMicros': timeExtentMicros ?? -1, 'timeExtentMicros': timeExtentMicros ?? -1,
'pid': pid ?? -1, 'pid': pid ?? -1,
@ -3676,9 +3702,7 @@ class CpuSamples extends Response {
return json; return json;
} }
String toString() => '[CpuSamples ' // String toString() => '[CpuSamples]';
'samplePeriod: ${samplePeriod}, maxStackDepth: ${maxStackDepth}, ' //
'sampleCount: ${sampleCount}, timeOriginMicros: ${timeOriginMicros}, timeExtentMicros: ${timeExtentMicros}, pid: ${pid}, functions: ${functions}, samples: ${samples}]';
} }
class CpuSamplesEvent { class CpuSamplesEvent {
@ -3694,6 +3718,13 @@ class CpuSamplesEvent {
/// The number of samples returned. /// The number of samples returned.
int? sampleCount; int? sampleCount;
/// The timespan the set of returned samples covers, in microseconds
/// (deprecated).
///
/// Note: this property is deprecated and will always return -1. Use
/// `timeExtentMicros` instead.
int? timeSpan;
/// The start of the period of time in which the returned samples were /// The start of the period of time in which the returned samples were
/// collected. /// collected.
int? timeOriginMicros; int? timeOriginMicros;
@ -3717,6 +3748,7 @@ class CpuSamplesEvent {
this.samplePeriod, this.samplePeriod,
this.maxStackDepth, this.maxStackDepth,
this.sampleCount, this.sampleCount,
this.timeSpan,
this.timeOriginMicros, this.timeOriginMicros,
this.timeExtentMicros, this.timeExtentMicros,
this.pid, this.pid,
@ -3728,6 +3760,7 @@ class CpuSamplesEvent {
samplePeriod = json['samplePeriod'] ?? -1; samplePeriod = json['samplePeriod'] ?? -1;
maxStackDepth = json['maxStackDepth'] ?? -1; maxStackDepth = json['maxStackDepth'] ?? -1;
sampleCount = json['sampleCount'] ?? -1; sampleCount = json['sampleCount'] ?? -1;
timeSpan = json['timeSpan'] ?? -1;
timeOriginMicros = json['timeOriginMicros'] ?? -1; timeOriginMicros = json['timeOriginMicros'] ?? -1;
timeExtentMicros = json['timeExtentMicros'] ?? -1; timeExtentMicros = json['timeExtentMicros'] ?? -1;
pid = json['pid'] ?? -1; pid = json['pid'] ?? -1;
@ -3745,6 +3778,7 @@ class CpuSamplesEvent {
'samplePeriod': samplePeriod ?? -1, 'samplePeriod': samplePeriod ?? -1,
'maxStackDepth': maxStackDepth ?? -1, 'maxStackDepth': maxStackDepth ?? -1,
'sampleCount': sampleCount ?? -1, 'sampleCount': sampleCount ?? -1,
'timeSpan': timeSpan ?? -1,
'timeOriginMicros': timeOriginMicros ?? -1, 'timeOriginMicros': timeOriginMicros ?? -1,
'timeExtentMicros': timeExtentMicros ?? -1, 'timeExtentMicros': timeExtentMicros ?? -1,
'pid': pid ?? -1, 'pid': pid ?? -1,
@ -3754,9 +3788,7 @@ class CpuSamplesEvent {
return json; return json;
} }
String toString() => '[CpuSamplesEvent ' // String toString() => '[CpuSamplesEvent]';
'samplePeriod: ${samplePeriod}, maxStackDepth: ${maxStackDepth}, ' //
'sampleCount: ${sampleCount}, timeOriginMicros: ${timeOriginMicros}, timeExtentMicros: ${timeExtentMicros}, pid: ${pid}, functions: ${functions}, samples: ${samples}]';
} }
/// See [getCpuSamples] and [CpuSamples]. /// See [getCpuSamples] and [CpuSamples].
@ -5991,24 +6023,15 @@ class InboundReference {
/// The object holding the inbound reference. /// The object holding the inbound reference.
ObjRef? source; ObjRef? source;
/// If source is a List, parentListIndex is the index of the inbound reference /// If source is a List, parentListIndex is the index of the inbound
/// (deprecated). /// reference.
///
/// Note: this property is deprecated and will be replaced by `parentField`.
@optional @optional
int? parentListIndex; int? parentListIndex;
/// If `source` is a `List`, `parentField` is the index of the inbound /// If source is a field of an object, parentField is the field containing the
/// reference. If `source` is a record, `parentField` is the field name of the /// inbound reference.
/// inbound reference. If `source` is an instance of any other kind,
/// `parentField` is the field containing the inbound reference.
///
/// Note: In v5.0 of the spec, `@Field` will no longer be a part of this
/// property's type, i.e. the type will become `string|int`.
///
/// [parentField] can be one of [FieldRef], [String] or [int].
@optional @optional
dynamic parentField; FieldRef? parentField;
InboundReference({ InboundReference({
this.source, this.source,
@ -6019,8 +6042,8 @@ class InboundReference {
InboundReference._fromJson(Map<String, dynamic> json) { InboundReference._fromJson(Map<String, dynamic> json) {
source = createServiceObject(json['source'], const ['ObjRef']) as ObjRef?; source = createServiceObject(json['source'], const ['ObjRef']) as ObjRef?;
parentListIndex = json['parentListIndex']; parentListIndex = json['parentListIndex'];
parentField = createServiceObject( parentField = createServiceObject(json['parentField'], const ['FieldRef'])
json['parentField'], const ['FieldRef', 'String', 'int']) as dynamic; as FieldRef?;
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -7118,9 +7141,7 @@ class RetainingObject {
ObjRef? value; ObjRef? value;
/// If `value` is a List, `parentListIndex` is the index where the previous /// If `value` is a List, `parentListIndex` is the index where the previous
/// object on the retaining path is located (deprecated). /// object on the retaining path is located.
///
/// Note: this property is deprecated and will be replaced by `parentField`.
@optional @optional
int? parentListIndex; int? parentListIndex;
@ -7131,10 +7152,8 @@ class RetainingObject {
/// If `value` is a non-List, non-Map object, `parentField` is the name of the /// If `value` is a non-List, non-Map object, `parentField` is the name of the
/// field containing the previous object on the retaining path. /// field containing the previous object on the retaining path.
///
/// [parentField] can be one of [String] or [int].
@optional @optional
dynamic parentField; String? parentField;
RetainingObject({ RetainingObject({
this.value, this.value,
@ -7148,9 +7167,7 @@ class RetainingObject {
parentListIndex = json['parentListIndex']; parentListIndex = json['parentListIndex'];
parentMapKey = parentMapKey =
createServiceObject(json['parentMapKey'], const ['ObjRef']) as ObjRef?; createServiceObject(json['parentMapKey'], const ['ObjRef']) as ObjRef?;
parentField = parentField = json['parentField'];
createServiceObject(json['parentField'], const ['String', 'int'])
as dynamic;
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -7160,7 +7177,7 @@ class RetainingObject {
}); });
_setIfNotNull(json, 'parentListIndex', parentListIndex); _setIfNotNull(json, 'parentListIndex', parentListIndex);
_setIfNotNull(json, 'parentMapKey', parentMapKey?.toJson()); _setIfNotNull(json, 'parentMapKey', parentMapKey?.toJson());
_setIfNotNull(json, 'parentField', parentField?.toJson()); _setIfNotNull(json, 'parentField', parentField);
return json; return json;
} }

View file

@ -7,7 +7,6 @@
library get_object_rpc_test; library get_object_rpc_test;
import 'dart:collection';
import 'dart:convert' show base64Decode; import 'dart:convert' show base64Decode;
import 'dart:typed_data'; import 'dart:typed_data';
@ -694,23 +693,19 @@ var tests = <IsolateTest>[
as InstanceRef; as InstanceRef;
final objectId = evalResult.id!; final objectId = evalResult.id!;
final result = await service.getObject(isolateId, objectId) as Instance; final result = await service.getObject(isolateId, objectId) as Instance;
expect(result.kind, InstanceKind.kRecord); expect(result.kind, '_Record');
expect(result.json!['_vmType'], 'Record'); expect(result.json!['_vmType'], 'Record');
expect(result.id, startsWith('objects/')); expect(result.id, startsWith('objects/'));
expect(result.valueAsString, isNull); expect(result.valueAsString, isNull);
expect(result.classRef!.name, '_Record'); expect(result.classRef!.name, '_Record');
expect(result.size, isPositive); expect(result.size, isPositive);
final fieldsMap = HashMap.fromEntries( final fields = result.fields!;
result.fields!.map((f) => MapEntry(f.name, f.value))); expect(fields.length, 4);
expect(fieldsMap.keys.length, 4); // TODO(derekx): Include field names in this test once they are accessible
expect(fieldsMap.containsKey(0), true); // through package:vm_service.
expect(fieldsMap[0].valueAsString, '1'); Set<String> fieldValues =
expect(fieldsMap.containsKey("x"), true); Set.from(fields.map((f) => f.value.valueAsString));
expect(fieldsMap["x"].valueAsString, '2'); expect(fieldValues.containsAll(['1', '2', '3.0', '4.0']), true);
expect(fieldsMap.containsKey(1), true);
expect(fieldsMap[1].valueAsString, '3.0');
expect(fieldsMap.containsKey("y"), true);
expect(fieldsMap["y"].valueAsString, '4.0');
}, },
// library. // library.

View file

@ -0,0 +1,112 @@
// Copyright (c) 2021, 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:async';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/test_helper.dart';
doThrow() {
throw "TheException"; // Line 13.
}
doCaught() {
try {
doThrow();
} catch (e) {
return "end of doCaught";
}
}
doUncaught() {
doThrow();
return "end of doUncaught";
}
final tests = <IsolateTest>[
(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id!);
final lib = await service.getObject(isolateRef.id!, isolate.rootLib!.id!);
Completer? onPaused;
Completer? onResume;
final stream = service.onDebugEvent;
final subscription = stream.listen((Event event) {
print("Event $event");
if (event.kind == EventKind.kPauseException) {
if (onPaused == null) throw "Unexpected pause event $event";
final t = onPaused;
onPaused = null;
t!.complete(event);
}
if (event.kind == EventKind.kResume) {
if (onResume == null) throw "Unexpected resume event $event";
final t = onResume;
onResume = null;
t!.complete(event);
}
});
await service.streamListen(EventStreams.kDebug);
test(String pauseMode, String expression, bool shouldPause,
bool shouldBeCaught) async {
print("Evaluating $expression with pause on $pauseMode exception");
// ignore: deprecated_member_use_from_same_package
await service.setExceptionPauseMode(isolate.id!, pauseMode);
late Completer t;
if (shouldPause) {
t = Completer();
onPaused = t;
}
final fres = service.evaluate(isolate.id!, lib.id!, expression);
if (shouldPause) {
await t.future;
final stack = await service.getStack(isolate.id!);
expect(stack.frames![0].function!.name, 'doThrow');
t = Completer();
onResume = t;
await service.resume(isolate.id!);
await t.future;
}
dynamic res = await fres;
if (shouldBeCaught) {
expect(res is InstanceRef, true);
expect(res.kind, 'String');
expect(res.valueAsString, equals("end of doCaught"));
} else {
print(res.json);
expect(res is ErrorRef, true);
res = await service.getObject(isolate.id!, res.id!);
expect(res is Error, true);
expect(res.exception.kind, 'String');
expect(res.exception.valueAsString, equals("TheException"));
}
}
await test("All", "doCaught()", true, true);
await test("All", "doUncaught()", true, false);
await test("Unhandled", "doCaught()", false, true);
await test("Unhandled", "doUncaught()", true, false);
await test("None", "doCaught()", false, true);
await test("None", "doUncaught()", false, false);
await subscription.cancel();
},
];
main([args = const <String>[]]) => runIsolateTests(
args,
tests,
'pause_on_exceptions_test.dart',
);

View file

@ -637,7 +637,7 @@ class SetCommand extends DebuggerCommand {
}; };
static Future _setBreakOnException(debugger, name, value) async { static Future _setBreakOnException(debugger, name, value) async {
var result = await debugger.isolate.setIsolatePauseMode(value); var result = await debugger.isolate.setExceptionPauseMode(value);
if (result.isError) { if (result.isError) {
debugger.console.print(result.toString()); debugger.console.print(result.toString());
} else { } else {

View file

@ -1886,8 +1886,8 @@ class Isolate extends ServiceObjectOwner implements M.Isolate {
return invokeRpc('setName', {'name': newName}); return invokeRpc('setName', {'name': newName});
} }
Future setIsolatePauseMode(String mode) { Future setExceptionPauseMode(String mode) {
return invokeRpc('setIsolatePauseMode', {'exceptionPauseMode': mode}); return invokeRpc('setExceptionPauseMode', {'mode': mode});
} }
Future<ServiceMap> getStack({int? limit}) { Future<ServiceMap> getStack({int? limit}) {

View file

@ -11,8 +11,8 @@ var tests = <VMTest>[
(VM vm) async { (VM vm) async {
final result = await vm.invokeRpcNoUpgrade('getVersion', {}); final result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], 'Version'); expect(result['type'], 'Version');
expect(result['major'], 4); expect(result['major'], 3);
expect(result['minor'], 0); expect(result['minor'], 62);
expect(result['_privateMajor'], 0); expect(result['_privateMajor'], 0);
expect(result['_privateMinor'], 0); expect(result['_privateMinor'], 0);
}, },

View file

@ -52,8 +52,8 @@ var tests = <IsolateTest>[
bool shouldBeCaught) async { bool shouldBeCaught) async {
print("Evaluating $expression with pause on $pauseMode exception"); print("Evaluating $expression with pause on $pauseMode exception");
expect( expect((await isolate.setExceptionPauseMode(pauseMode)) is DartError,
(await isolate.setIsolatePauseMode(pauseMode)) is DartError, isFalse); isFalse);
var t; var t;
if (shouldPause) { if (shouldPause) {

View file

@ -632,7 +632,7 @@ class SetCommand extends DebuggerCommand {
}; };
static Future _setBreakOnException(debugger, name, value) async { static Future _setBreakOnException(debugger, name, value) async {
var result = await debugger.isolate.setIsolatePauseMode(value); var result = await debugger.isolate.setExceptionPauseMode(value);
if (result.isError) { if (result.isError) {
debugger.console.print(result.toString()); debugger.console.print(result.toString());
} else { } else {

View file

@ -1894,8 +1894,8 @@ class Isolate extends ServiceObjectOwner implements M.Isolate {
return invokeRpc('setName', {'name': newName}); return invokeRpc('setName', {'name': newName});
} }
Future setIsolatePauseMode(String mode) { Future setExceptionPauseMode(String mode) {
return invokeRpc('setIsolatePauseMode', {'exceptionPauseMode': mode}); return invokeRpc('setExceptionPauseMode', {'mode': mode});
} }
Future<ServiceMap> getStack({int limit}) { Future<ServiceMap> getStack({int limit}) {

View file

@ -11,8 +11,8 @@ var tests = <VMTest>[
(VM vm) async { (VM vm) async {
final result = await vm.invokeRpcNoUpgrade('getVersion', {}); final result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version')); expect(result['type'], equals('Version'));
expect(result['major'], equals(4)); expect(result['major'], equals(3));
expect(result['minor'], equals(0)); expect(result['minor'], equals(62));
expect(result['_privateMajor'], equals(0)); expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0)); expect(result['_privateMinor'], equals(0));
}, },

View file

@ -52,8 +52,8 @@ var tests = <IsolateTest>[
bool shouldBeCaught) async { bool shouldBeCaught) async {
print("Evaluating $expression with pause on $pauseMode exception"); print("Evaluating $expression with pause on $pauseMode exception");
expect( expect((await isolate.setExceptionPauseMode(pauseMode)) is DartError,
(await isolate.setIsolatePauseMode(pauseMode)) is DartError, isFalse); isFalse);
var t; var t;
if (shouldPause) { if (shouldPause) {

View file

@ -1124,8 +1124,8 @@ void Instance::PrintSharedInstanceJSON(JSONObject* jsobj,
if (!field.is_static()) { if (!field.is_static()) {
field_value = GetField(field); field_value = GetField(field);
JSONObject jsfield(&jsarr); JSONObject jsfield(&jsarr);
jsfield.AddProperty("type", "BoundField");
jsfield.AddProperty("decl", field); jsfield.AddProperty("decl", field);
jsfield.AddProperty("name", field.UserVisibleNameCString());
jsfield.AddProperty("value", field_value); jsfield.AddProperty("value", field_value);
} }
} }
@ -1219,7 +1219,7 @@ void FunctionType::PrintJSONImpl(JSONStream* stream, bool ref) const {
void RecordType::PrintJSONImpl(JSONStream* stream, bool ref) const { void RecordType::PrintJSONImpl(JSONStream* stream, bool ref) const {
JSONObject jsobj(stream); JSONObject jsobj(stream);
PrintSharedInstanceJSON(&jsobj, ref); PrintSharedInstanceJSON(&jsobj, ref);
jsobj.AddProperty("kind", "RecordType"); jsobj.AddProperty("kind", "_RecordType");
if (ref) { if (ref) {
return; return;
} }
@ -1630,7 +1630,7 @@ void Closure::PrintJSONImpl(JSONStream* stream, bool ref) const {
void Record::PrintJSONImpl(JSONStream* stream, bool ref) const { void Record::PrintJSONImpl(JSONStream* stream, bool ref) const {
JSONObject jsobj(stream); JSONObject jsobj(stream);
PrintSharedInstanceJSON(&jsobj, ref); PrintSharedInstanceJSON(&jsobj, ref);
jsobj.AddProperty("kind", "Record"); jsobj.AddProperty("kind", "_Record");
if (ref) { if (ref) {
return; return;
} }

View file

@ -1559,6 +1559,9 @@ void Profile::PrintHeaderJSON(JSONObject* obj) {
obj->AddProperty("maxStackDepth", obj->AddProperty("maxStackDepth",
static_cast<intptr_t>(FLAG_max_profile_depth)); static_cast<intptr_t>(FLAG_max_profile_depth));
obj->AddProperty("sampleCount", sample_count()); obj->AddProperty("sampleCount", sample_count());
// TODO(bkonyi): remove timeSpan after next major revision.
ASSERT(SERVICE_PROTOCOL_MAJOR_VERSION == 3);
obj->AddProperty64("timeSpan", -1);
obj->AddPropertyTimeMicros("timeOriginMicros", min_time()); obj->AddPropertyTimeMicros("timeOriginMicros", min_time());
obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan()); obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan());
obj->AddProperty64("pid", pid); obj->AddProperty64("pid", pid);

View file

@ -2321,7 +2321,6 @@ static void PrintInboundReferences(Thread* thread,
(slot_offset.Value() - Array::element_offset(0)) / (slot_offset.Value() - Array::element_offset(0)) /
Array::kBytesPerElement; Array::kBytesPerElement;
jselement.AddProperty("parentListIndex", element_index); jselement.AddProperty("parentListIndex", element_index);
jselement.AddProperty("parentField", element_index);
} else if (source.IsRecord()) { } else if (source.IsRecord()) {
AddParentFieldToResponseBasedOnRecord(thread, &field_names, &name, AddParentFieldToResponseBasedOnRecord(thread, &field_names, &name,
jselement, Record::Cast(source), jselement, Record::Cast(source),
@ -2352,7 +2351,6 @@ static void PrintInboundReferences(Thread* thread,
(slot_offset.Value() - Context::variable_offset(0)) / (slot_offset.Value() - Context::variable_offset(0)) /
Context::kBytesPerElement; Context::kBytesPerElement;
jselement.AddProperty("parentListIndex", element_index); jselement.AddProperty("parentListIndex", element_index);
jselement.AddProperty("parentField", element_index);
} else { } else {
jselement.AddProperty("_parentWordOffset", slot_offset.Value()); jselement.AddProperty("_parentWordOffset", slot_offset.Value());
} }
@ -2447,7 +2445,6 @@ static void PrintRetainingPath(Thread* thread,
(slot_offset.Value() - Array::element_offset(0)) / (slot_offset.Value() - Array::element_offset(0)) /
Array::kBytesPerElement; Array::kBytesPerElement;
jselement.AddProperty("parentListIndex", element_index); jselement.AddProperty("parentListIndex", element_index);
jselement.AddProperty("parentField", element_index);
} else if (element.IsRecord()) { } else if (element.IsRecord()) {
AddParentFieldToResponseBasedOnRecord(thread, &field_names, &name, AddParentFieldToResponseBasedOnRecord(thread, &field_names, &name,
jselement, Record::Cast(element), jselement, Record::Cast(element),
@ -2494,7 +2491,6 @@ static void PrintRetainingPath(Thread* thread,
(slot_offset.Value() - Context::variable_offset(0)) / (slot_offset.Value() - Context::variable_offset(0)) /
Context::kBytesPerElement; Context::kBytesPerElement;
jselement.AddProperty("parentListIndex", element_index); jselement.AddProperty("parentListIndex", element_index);
jselement.AddProperty("parentField", element_index);
} else { } else {
jselement.AddProperty("_parentWordOffset", slot_offset.Value()); jselement.AddProperty("_parentWordOffset", slot_offset.Value());
} }
@ -5419,6 +5415,27 @@ static const MethodParameter* const set_exception_pause_mode_params[] = {
NULL, NULL,
}; };
static void SetExceptionPauseMode(Thread* thread, JSONStream* js) {
const char* mode = js->LookupParam("mode");
if (mode == NULL) {
PrintMissingParamError(js, "mode");
return;
}
Dart_ExceptionPauseInfo info =
EnumMapper(mode, exception_pause_mode_names, exception_pause_mode_values);
if (info == kInvalidExceptionPauseInfo) {
PrintInvalidParamError(js, "mode");
return;
}
Isolate* isolate = thread->isolate();
isolate->debugger()->SetExceptionPauseInfo(info);
if (Service::debug_stream.enabled()) {
ServiceEvent event(isolate, ServiceEvent::kDebuggerSettingsUpdate);
Service::HandleEvent(&event);
}
PrintSuccess(js);
}
static const MethodParameter* const set_isolate_pause_mode_params[] = { static const MethodParameter* const set_isolate_pause_mode_params[] = {
ISOLATE_PARAMETER, ISOLATE_PARAMETER,
new EnumParameter("exceptionPauseMode", false, exception_pause_mode_names), new EnumParameter("exceptionPauseMode", false, exception_pause_mode_names),
@ -5872,6 +5889,8 @@ static const ServiceMethodDescriptor service_methods_[] = {
evaluate_compiled_expression_params }, evaluate_compiled_expression_params },
{ "setBreakpointState", SetBreakpointState, { "setBreakpointState", SetBreakpointState,
set_breakpoint_state_params }, set_breakpoint_state_params },
{ "setExceptionPauseMode", SetExceptionPauseMode,
set_exception_pause_mode_params },
{ "setIsolatePauseMode", SetIsolatePauseMode, { "setIsolatePauseMode", SetIsolatePauseMode,
set_isolate_pause_mode_params }, set_isolate_pause_mode_params },
{ "setFlag", SetFlag, { "setFlag", SetFlag,

View file

@ -16,8 +16,8 @@
namespace dart { namespace dart {
#define SERVICE_PROTOCOL_MAJOR_VERSION 4 #define SERVICE_PROTOCOL_MAJOR_VERSION 3
#define SERVICE_PROTOCOL_MINOR_VERSION 0 #define SERVICE_PROTOCOL_MINOR_VERSION 62
class Array; class Array;
class EmbedderServiceHandler; class EmbedderServiceHandler;

View file

@ -1,8 +1,8 @@
# Dart VM Service Protocol 4.0 # Dart VM Service Protocol 3.62
> Please post feedback to the [observatory-discuss group][discuss-list] > Please post feedback to the [observatory-discuss group][discuss-list]
This document describes of _version 4.0_ of the Dart VM Service Protocol. This This document describes of _version 3.62_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine. protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag. To use the Service Protocol, start the VM with the *--observe* flag.
@ -71,6 +71,7 @@ The Service Protocol uses [JSON-RPC 2.0][].
- [removeBreakpoint](#removebreakpoint) - [removeBreakpoint](#removebreakpoint)
- [resume](#resume) - [resume](#resume)
- [setBreakpointState](#setbreakpointstate) - [setBreakpointState](#setbreakpointstate)
- [setExceptionPauseMode](#setexceptionpausemode)
- [setFlag](#setflag) - [setFlag](#setflag)
- [setLibraryDebuggable](#setlibrarydebuggable) - [setLibraryDebuggable](#setlibrarydebuggable)
- [setName](#setname) - [setName](#setname)
@ -120,7 +121,7 @@ The Service Protocol uses [JSON-RPC 2.0][].
- [NativeFunction](#nativefunction) - [NativeFunction](#nativefunction)
- [Null](#null) - [Null](#null)
- [Object](#object) - [Object](#object)
- [Parameter](#parameter) - [Parameter](#parameter)[
- [PortList](#portlist) - [PortList](#portlist)
- [ReloadReport](#reloadreport) - [ReloadReport](#reloadreport)
- [Response](#response) - [Response](#response)
@ -143,7 +144,7 @@ The Service Protocol uses [JSON-RPC 2.0][].
- [TimelineFlags](#timelineflags) - [TimelineFlags](#timelineflags)
- [Timestamp](#timestamp) - [Timestamp](#timestamp)
- [TypeArguments](#typearguments) - [TypeArguments](#typearguments)
- [TypeParameters](#typeparameters) - [TypeParameters](#typeparameters)[
- [UnresolvedSourceLocation](#unresolvedsourcelocation) - [UnresolvedSourceLocation](#unresolvedsourcelocation)
- [UriList](#urilist) - [UriList](#urilist)
- [Version](#version) - [Version](#version)
@ -1383,6 +1384,25 @@ The returned [Breakpoint](#breakpoint) is the updated breakpoint with its new
values. values.
See [Breakpoint](#breakpoint). See [Breakpoint](#breakpoint).
### setExceptionPauseMode
```
@deprecated('Use setIsolatePauseMode instead')
Success|Sentinel setExceptionPauseMode(string isolateId,
ExceptionPauseMode mode)
```
The _setExceptionPauseMode_ RPC is used to control if an isolate pauses when
an exception is thrown.
mode | meaning
---- | -------
None | Do not pause isolate on thrown exceptions
Unhandled | Pause isolate on unhandled exceptions
All | Pause isolate on all thrown exceptions
If _isolateId_ refers to an isolate which has exited, then the
_Collected_ [Sentinel](#sentinel) is returned.
### setIsolatePauseMode ### setIsolatePauseMode
@ -1397,6 +1417,9 @@ pause due to a change in execution state.
The _shouldPauseOnExit_ parameter specify whether the target isolate should pause on exit. The _shouldPauseOnExit_ parameter specify whether the target isolate should pause on exit.
The _setExceptionPauseMode_ RPC is used to control if an isolate pauses when
an exception is thrown.
mode | meaning mode | meaning
---- | ------- ---- | -------
None | Do not pause isolate on thrown exceptions None | Do not pause isolate on thrown exceptions
@ -1685,12 +1708,7 @@ class AllocationProfile extends Response {
``` ```
class BoundField { class BoundField {
// Provided for fields of instances that are NOT of the following instance kinds:
// Record
//
// Note: this property is deprecated and will be replaced by `name`.
@Field decl; @Field decl;
string|int name;
@Instance|Sentinel value; @Instance|Sentinel value;
} }
``` ```
@ -1962,6 +1980,12 @@ class CpuSamples extends Response {
// The number of samples returned. // The number of samples returned.
int sampleCount; int sampleCount;
// The timespan the set of returned samples covers, in microseconds (deprecated).
//
// Note: this property is deprecated and will always return -1. Use `timeExtentMicros`
// instead.
int timeSpan;
// The start of the period of time in which the returned samples were // The start of the period of time in which the returned samples were
// collected. // collected.
int timeOriginMicros; int timeOriginMicros;
@ -1998,6 +2022,12 @@ class CpuSamplesEvent {
// The number of samples returned. // The number of samples returned.
int sampleCount; int sampleCount;
// The timespan the set of returned samples covers, in microseconds (deprecated).
//
// Note: this property is deprecated and will always return -1. Use `timeExtentMicros`
// instead.
int timeSpan;
// The start of the period of time in which the returned samples were // The start of the period of time in which the returned samples were
// collected. // collected.
int timeOriginMicros; int timeOriginMicros;
@ -3103,9 +3133,6 @@ enum InstanceKind {
Float32x4List, Float32x4List,
Float64x2List, Float64x2List,
// An instance of the Dart class Record.
Record,
// An instance of the Dart class StackTrace. // An instance of the Dart class StackTrace.
StackTrace, StackTrace,
@ -3137,9 +3164,6 @@ enum InstanceKind {
// An instance of the Dart class FunctionType. // An instance of the Dart class FunctionType.
FunctionType, FunctionType,
// An instance of the Dart class RecordType.
RecordType,
// An instance of the Dart class BoundedType. // An instance of the Dart class BoundedType.
BoundedType, BoundedType,
@ -3320,21 +3344,12 @@ class InboundReference {
// The object holding the inbound reference. // The object holding the inbound reference.
@Object source; @Object source;
// If source is a List, parentListIndex is the index of the inbound reference (deprecated). // If source is a List, parentListIndex is the index of the inbound reference.
//
// Note: this property is deprecated and will be replaced by `parentField`.
int parentListIndex [optional]; int parentListIndex [optional];
// If `source` is a `List`, `parentField` is the index of the inbound // If source is a field of an object, parentField is the field containing the
// reference. // inbound reference.
// If `source` is a record, `parentField` is the field name of the inbound @Field parentField [optional];
// reference.
// If `source` is an instance of any other kind, `parentField` is the field
// containing the inbound reference.
//
// Note: In v5.0 of the spec, `@Field` will no longer be a part of this
// property's type, i.e. the type will become `string|int`.
@Field|string|int parentField [optional];
} }
``` ```
@ -3746,9 +3761,7 @@ class RetainingObject {
@Object value; @Object value;
// If `value` is a List, `parentListIndex` is the index where the previous // If `value` is a List, `parentListIndex` is the index where the previous
// object on the retaining path is located (deprecated). // object on the retaining path is located.
//
// Note: this property is deprecated and will be replaced by `parentField`.
int parentListIndex [optional]; int parentListIndex [optional];
// If `value` is a Map, `parentMapKey` is the key mapping to the previous // If `value` is a Map, `parentMapKey` is the key mapping to the previous
@ -3757,7 +3770,7 @@ class RetainingObject {
// If `value` is a non-List, non-Map object, `parentField` is the name of the // If `value` is a non-List, non-Map object, `parentField` is the name of the
// field containing the previous object on the retaining path. // field containing the previous object on the retaining path.
string|int parentField [optional]; string parentField [optional];
} }
``` ```
@ -4402,6 +4415,5 @@ version | comments
3.60 | Added `gcType` property to `Event`. 3.60 | Added `gcType` property to `Event`.
3.61 | Added `isolateGroupId` property to `@Isolate` and `Isolate`. 3.61 | Added `isolateGroupId` property to `@Isolate` and `Isolate`.
3.62 | Added `Set` to `InstanceKind`. 3.62 | Added `Set` to `InstanceKind`.
4.0 | Added `Record` and `RecordType` `InstanceKind`s, added a deprecation notice to the `decl` property of `BoundField`, added `name` property to `BoundField`, added a deprecation notice to the `parentListIndex` property of `InboundReference`, changed the type of the `parentField` property of `InboundReference` from `@Field` to `@Field\|string\|int`, added a deprecation notice to the `parentListIndex` property of `RetainingObject`, changed the type of the `parentField` property of `RetainingObject` from `string` to `string\|int`, removed the deprecated `setExceptionPauseMode` procedure, removed the deprecated `timeSpan` property from `CpuSamples`, and removed the deprecated `timeSpan` property from `CpuSamplesEvent`.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss