diff --git a/pkg/dds_service_extensions/lib/dds_service_extensions.dart b/pkg/dds_service_extensions/lib/dds_service_extensions.dart index e28fb7b5eba..702cf58b791 100644 --- a/pkg/dds_service_extensions/lib/dds_service_extensions.dart +++ b/pkg/dds_service_extensions/lib/dds_service_extensions.dart @@ -200,6 +200,7 @@ class CachedCpuSamples extends CpuSamples { required int? samplePeriod, required int? maxStackDepth, required int? sampleCount, + required int? timeSpan, required int? timeOriginMicros, required int? timeExtentMicros, required int? pid, @@ -209,6 +210,7 @@ class CachedCpuSamples extends CpuSamples { samplePeriod: samplePeriod, maxStackDepth: maxStackDepth, sampleCount: sampleCount, + timeSpan: timeSpan, timeOriginMicros: timeOriginMicros, timeExtentMicros: timeExtentMicros, pid: pid, @@ -223,6 +225,7 @@ class CachedCpuSamples extends CpuSamples { samplePeriod: json['samplePeriod'] ?? -1, maxStackDepth: json['maxStackDepth'] ?? -1, sampleCount: json['sampleCount'] ?? -1, + timeSpan: json['timeSpan'] ?? -1, timeOriginMicros: json['timeOriginMicros'] ?? -1, timeExtentMicros: json['timeExtentMicros'] ?? -1, pid: json['pid'] ?? -1, diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore index 9e1e42e5cdf..5fe823ee8da 100644 --- a/pkg/vm_service/java/.gitignore +++ b/pkg/vm_service/java/.gitignore @@ -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/RequestHeapSnapshotConsumer.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/SetIsolatePauseModeConsumer.java src/org/dartlang/vm/service/consumer/SetLibraryDebuggableConsumer.java diff --git a/pkg/vm_service/java/test/org/dartlang/vm/service/VmServiceTest.java b/pkg/vm_service/java/test/org/dartlang/vm/service/VmServiceTest.java index 5b31a47bc46..aa191edb764 100644 --- a/pkg/vm_service/java/test/org/dartlang/vm/service/VmServiceTest.java +++ b/pkg/vm_service/java/test/org/dartlang/vm/service/VmServiceTest.java @@ -587,17 +587,17 @@ public class VmServiceTest { private static void vmPauseOnException(IsolateRef isolate, ExceptionPauseMode mode) { System.out.println("Request pause on exception: " + mode); final OpLatch latch = new OpLatch(); - vmService.setIsolatePauseMode(isolate.getId(), mode, new SuccessConsumer() { - @Override - public void onError(RPCError error) { - showRPCError(error); - } + vmService.setExceptionPauseMode(isolate.getId(), mode, new SuccessConsumer() { + @Override + public void onError(RPCError error) { + showRPCError(error); + } - @Override - public void received(Success response) { - System.out.println("Successfully set pause on exception"); - latch.opComplete(); - } + @Override + public void received(Success response) { + System.out.println("Successfully set pause on exception"); + latch.opComplete(); + } }); latch.waitAndAssertOpComplete(); } diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties index db1ef8e5fa6..8822aaf8ba2 100644 --- a/pkg/vm_service/java/version.properties +++ b/pkg/vm_service/java/version.properties @@ -1 +1 @@ -version=4.0 +version=3.62 diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart index 0e633ffbde0..7b4745f198b 100644 --- a/pkg/vm_service/lib/src/vm_service.dart +++ b/pkg/vm_service/lib/src/vm_service.dart @@ -26,7 +26,7 @@ export 'snapshot_graph.dart' HeapSnapshotObjectNoData, HeapSnapshotObjectNullData; -const String vmServiceVersion = '4.0.0'; +const String vmServiceVersion = '3.62.0'; /// @optional const String optional = 'optional'; @@ -236,6 +236,7 @@ Map> _methodReturnTypes = { 'requestHeapSnapshot': const ['Success'], 'resume': const ['Success'], 'setBreakpointState': const ['Breakpoint'], + 'setExceptionPauseMode': const ['Success'], 'setIsolatePauseMode': const ['Success'], 'setFlag': const ['Success', 'Error'], 'setLibraryDebuggable': const ['Success'], @@ -1076,12 +1077,33 @@ abstract class VmServiceInterface { Future setBreakpointState( 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 setExceptionPauseMode( + String isolateId, /*ExceptionPauseMode*/ String mode); + /// The `setIsolatePauseMode` RPC is used to control if or when an isolate /// will pause due to a change in execution state. /// /// 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 /// ---- | ------- /// None | Do not pause isolate on thrown exceptions @@ -1576,6 +1598,13 @@ class VmServerConnection { params['enable'], ); break; + case 'setExceptionPauseMode': + // ignore: deprecated_member_use_from_same_package + response = await _serviceImplementation.setExceptionPauseMode( + params!['isolateId'], + params['mode'], + ); + break; case 'setIsolatePauseMode': response = await _serviceImplementation.setIsolatePauseMode( params!['isolateId'], @@ -2120,6 +2149,12 @@ class VmService implements VmServiceInterface { 'enable': enable }); + @Deprecated('Use setIsolatePauseMode instead') + @override + Future setExceptionPauseMode( + String isolateId, /*ExceptionPauseMode*/ String mode) => + _call('setExceptionPauseMode', {'isolateId': isolateId, 'mode': mode}); + @override Future setIsolatePauseMode(String isolateId, {/*ExceptionPauseMode*/ String? exceptionPauseMode, @@ -2682,9 +2717,6 @@ class InstanceKind { static const String kFloat32x4List = 'Float32x4List'; static const String kFloat64x2List = 'Float64x2List'; - /// An instance of the Dart class Record. - static const String kRecord = 'Record'; - /// An instance of the Dart class StackTrace. static const String kStackTrace = 'StackTrace'; @@ -2716,9 +2748,6 @@ class InstanceKind { /// An instance of the Dart class 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. static const String kBoundedType = 'BoundedType'; @@ -2878,29 +2907,18 @@ class BoundField { static BoundField? parse(Map? 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; - /// [name] can be one of [String] or [int]. - dynamic name; - /// [value] can be one of [InstanceRef] or [Sentinel]. dynamic value; BoundField({ this.decl, - this.name, this.value, }); BoundField._fromJson(Map json) { decl = createServiceObject(json['decl'], const ['FieldRef']) as FieldRef?; - name = - createServiceObject(json['name'], const ['String', 'int']) as dynamic; value = createServiceObject(json['value'], const ['InstanceRef', 'Sentinel']) as dynamic; @@ -2910,14 +2928,12 @@ class BoundField { final json = {}; json.addAll({ 'decl': decl?.toJson(), - 'name': name?.toJson(), 'value': value?.toJson(), }); return json; } - String toString() => - '[BoundField decl: ${decl}, name: ${name}, value: ${value}]'; + String toString() => '[BoundField decl: ${decl}, value: ${value}]'; } /// 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. 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 /// collected. int? timeOriginMicros; @@ -3633,6 +3656,7 @@ class CpuSamples extends Response { this.samplePeriod, this.maxStackDepth, this.sampleCount, + this.timeSpan, this.timeOriginMicros, this.timeExtentMicros, this.pid, @@ -3644,6 +3668,7 @@ class CpuSamples extends Response { samplePeriod = json['samplePeriod'] ?? -1; maxStackDepth = json['maxStackDepth'] ?? -1; sampleCount = json['sampleCount'] ?? -1; + timeSpan = json['timeSpan'] ?? -1; timeOriginMicros = json['timeOriginMicros'] ?? -1; timeExtentMicros = json['timeExtentMicros'] ?? -1; pid = json['pid'] ?? -1; @@ -3667,6 +3692,7 @@ class CpuSamples extends Response { 'samplePeriod': samplePeriod ?? -1, 'maxStackDepth': maxStackDepth ?? -1, 'sampleCount': sampleCount ?? -1, + 'timeSpan': timeSpan ?? -1, 'timeOriginMicros': timeOriginMicros ?? -1, 'timeExtentMicros': timeExtentMicros ?? -1, 'pid': pid ?? -1, @@ -3676,9 +3702,7 @@ class CpuSamples extends Response { return json; } - String toString() => '[CpuSamples ' // - 'samplePeriod: ${samplePeriod}, maxStackDepth: ${maxStackDepth}, ' // - 'sampleCount: ${sampleCount}, timeOriginMicros: ${timeOriginMicros}, timeExtentMicros: ${timeExtentMicros}, pid: ${pid}, functions: ${functions}, samples: ${samples}]'; + String toString() => '[CpuSamples]'; } class CpuSamplesEvent { @@ -3694,6 +3718,13 @@ class CpuSamplesEvent { /// The number of samples returned. 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 /// collected. int? timeOriginMicros; @@ -3717,6 +3748,7 @@ class CpuSamplesEvent { this.samplePeriod, this.maxStackDepth, this.sampleCount, + this.timeSpan, this.timeOriginMicros, this.timeExtentMicros, this.pid, @@ -3728,6 +3760,7 @@ class CpuSamplesEvent { samplePeriod = json['samplePeriod'] ?? -1; maxStackDepth = json['maxStackDepth'] ?? -1; sampleCount = json['sampleCount'] ?? -1; + timeSpan = json['timeSpan'] ?? -1; timeOriginMicros = json['timeOriginMicros'] ?? -1; timeExtentMicros = json['timeExtentMicros'] ?? -1; pid = json['pid'] ?? -1; @@ -3745,6 +3778,7 @@ class CpuSamplesEvent { 'samplePeriod': samplePeriod ?? -1, 'maxStackDepth': maxStackDepth ?? -1, 'sampleCount': sampleCount ?? -1, + 'timeSpan': timeSpan ?? -1, 'timeOriginMicros': timeOriginMicros ?? -1, 'timeExtentMicros': timeExtentMicros ?? -1, 'pid': pid ?? -1, @@ -3754,9 +3788,7 @@ class CpuSamplesEvent { return json; } - String toString() => '[CpuSamplesEvent ' // - 'samplePeriod: ${samplePeriod}, maxStackDepth: ${maxStackDepth}, ' // - 'sampleCount: ${sampleCount}, timeOriginMicros: ${timeOriginMicros}, timeExtentMicros: ${timeExtentMicros}, pid: ${pid}, functions: ${functions}, samples: ${samples}]'; + String toString() => '[CpuSamplesEvent]'; } /// See [getCpuSamples] and [CpuSamples]. @@ -5991,24 +6023,15 @@ class InboundReference { /// The object holding the inbound reference. ObjRef? source; - /// If source is a List, parentListIndex is the index of the inbound reference - /// (deprecated). - /// - /// Note: this property is deprecated and will be replaced by `parentField`. + /// If source is a List, parentListIndex is the index of the inbound + /// reference. @optional int? parentListIndex; - /// If `source` is a `List`, `parentField` is the index of the inbound - /// reference. If `source` is a record, `parentField` is the field name of the - /// 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]. + /// If source is a field of an object, parentField is the field containing the + /// inbound reference. @optional - dynamic parentField; + FieldRef? parentField; InboundReference({ this.source, @@ -6019,8 +6042,8 @@ class InboundReference { InboundReference._fromJson(Map json) { source = createServiceObject(json['source'], const ['ObjRef']) as ObjRef?; parentListIndex = json['parentListIndex']; - parentField = createServiceObject( - json['parentField'], const ['FieldRef', 'String', 'int']) as dynamic; + parentField = createServiceObject(json['parentField'], const ['FieldRef']) + as FieldRef?; } Map toJson() { @@ -7118,9 +7141,7 @@ class RetainingObject { ObjRef? value; /// If `value` is a List, `parentListIndex` is the index where the previous - /// object on the retaining path is located (deprecated). - /// - /// Note: this property is deprecated and will be replaced by `parentField`. + /// object on the retaining path is located. @optional int? parentListIndex; @@ -7131,10 +7152,8 @@ class RetainingObject { /// If `value` is a non-List, non-Map object, `parentField` is the name of the /// field containing the previous object on the retaining path. - /// - /// [parentField] can be one of [String] or [int]. @optional - dynamic parentField; + String? parentField; RetainingObject({ this.value, @@ -7148,9 +7167,7 @@ class RetainingObject { parentListIndex = json['parentListIndex']; parentMapKey = createServiceObject(json['parentMapKey'], const ['ObjRef']) as ObjRef?; - parentField = - createServiceObject(json['parentField'], const ['String', 'int']) - as dynamic; + parentField = json['parentField']; } Map toJson() { @@ -7160,7 +7177,7 @@ class RetainingObject { }); _setIfNotNull(json, 'parentListIndex', parentListIndex); _setIfNotNull(json, 'parentMapKey', parentMapKey?.toJson()); - _setIfNotNull(json, 'parentField', parentField?.toJson()); + _setIfNotNull(json, 'parentField', parentField); return json; } diff --git a/pkg/vm_service/test/get_object_rpc_test.dart b/pkg/vm_service/test/get_object_rpc_test.dart index 0fe673aa690..34f880a0b63 100644 --- a/pkg/vm_service/test/get_object_rpc_test.dart +++ b/pkg/vm_service/test/get_object_rpc_test.dart @@ -7,7 +7,6 @@ library get_object_rpc_test; -import 'dart:collection'; import 'dart:convert' show base64Decode; import 'dart:typed_data'; @@ -694,23 +693,19 @@ var tests = [ as InstanceRef; final objectId = evalResult.id!; 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.id, startsWith('objects/')); expect(result.valueAsString, isNull); expect(result.classRef!.name, '_Record'); expect(result.size, isPositive); - final fieldsMap = HashMap.fromEntries( - result.fields!.map((f) => MapEntry(f.name, f.value))); - expect(fieldsMap.keys.length, 4); - expect(fieldsMap.containsKey(0), true); - expect(fieldsMap[0].valueAsString, '1'); - expect(fieldsMap.containsKey("x"), true); - expect(fieldsMap["x"].valueAsString, '2'); - expect(fieldsMap.containsKey(1), true); - expect(fieldsMap[1].valueAsString, '3.0'); - expect(fieldsMap.containsKey("y"), true); - expect(fieldsMap["y"].valueAsString, '4.0'); + final fields = result.fields!; + expect(fields.length, 4); + // TODO(derekx): Include field names in this test once they are accessible + // through package:vm_service. + Set fieldValues = + Set.from(fields.map((f) => f.value.valueAsString)); + expect(fieldValues.containsAll(['1', '2', '3.0', '4.0']), true); }, // library. diff --git a/pkg/vm_service/test/pause_on_exceptions_legacy_test.dart b/pkg/vm_service/test/pause_on_exceptions_legacy_test.dart new file mode 100644 index 00000000000..21ff3a8d167 --- /dev/null +++ b/pkg/vm_service/test/pause_on_exceptions_legacy_test.dart @@ -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 = [ + (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 []]) => runIsolateTests( + args, + tests, + 'pause_on_exceptions_test.dart', + ); diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart index 48fad75d407..a4163a00628 100644 --- a/runtime/observatory/lib/src/elements/debugger.dart +++ b/runtime/observatory/lib/src/elements/debugger.dart @@ -637,7 +637,7 @@ class SetCommand extends DebuggerCommand { }; static Future _setBreakOnException(debugger, name, value) async { - var result = await debugger.isolate.setIsolatePauseMode(value); + var result = await debugger.isolate.setExceptionPauseMode(value); if (result.isError) { debugger.console.print(result.toString()); } else { diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart index d4b4505f33d..81d1cea8610 100644 --- a/runtime/observatory/lib/src/service/object.dart +++ b/runtime/observatory/lib/src/service/object.dart @@ -1886,8 +1886,8 @@ class Isolate extends ServiceObjectOwner implements M.Isolate { return invokeRpc('setName', {'name': newName}); } - Future setIsolatePauseMode(String mode) { - return invokeRpc('setIsolatePauseMode', {'exceptionPauseMode': mode}); + Future setExceptionPauseMode(String mode) { + return invokeRpc('setExceptionPauseMode', {'mode': mode}); } Future getStack({int? limit}) { diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart index 2d1ea37c4e5..351000db52b 100644 --- a/runtime/observatory/tests/service/get_version_rpc_test.dart +++ b/runtime/observatory/tests/service/get_version_rpc_test.dart @@ -11,8 +11,8 @@ var tests = [ (VM vm) async { final result = await vm.invokeRpcNoUpgrade('getVersion', {}); expect(result['type'], 'Version'); - expect(result['major'], 4); - expect(result['minor'], 0); + expect(result['major'], 3); + expect(result['minor'], 62); expect(result['_privateMajor'], 0); expect(result['_privateMinor'], 0); }, diff --git a/runtime/observatory/tests/service/pause_on_exceptions_test.dart b/runtime/observatory/tests/service/pause_on_exceptions_test.dart index f73fdb87e15..35bd59e5783 100644 --- a/runtime/observatory/tests/service/pause_on_exceptions_test.dart +++ b/runtime/observatory/tests/service/pause_on_exceptions_test.dart @@ -52,8 +52,8 @@ var tests = [ bool shouldBeCaught) async { print("Evaluating $expression with pause on $pauseMode exception"); - expect( - (await isolate.setIsolatePauseMode(pauseMode)) is DartError, isFalse); + expect((await isolate.setExceptionPauseMode(pauseMode)) is DartError, + isFalse); var t; if (shouldPause) { diff --git a/runtime/observatory_2/lib/src/elements/debugger.dart b/runtime/observatory_2/lib/src/elements/debugger.dart index 9070138e53a..b63d3499b72 100644 --- a/runtime/observatory_2/lib/src/elements/debugger.dart +++ b/runtime/observatory_2/lib/src/elements/debugger.dart @@ -632,7 +632,7 @@ class SetCommand extends DebuggerCommand { }; static Future _setBreakOnException(debugger, name, value) async { - var result = await debugger.isolate.setIsolatePauseMode(value); + var result = await debugger.isolate.setExceptionPauseMode(value); if (result.isError) { debugger.console.print(result.toString()); } else { diff --git a/runtime/observatory_2/lib/src/service/object.dart b/runtime/observatory_2/lib/src/service/object.dart index 9acde0edf8f..63bf64f15d9 100644 --- a/runtime/observatory_2/lib/src/service/object.dart +++ b/runtime/observatory_2/lib/src/service/object.dart @@ -1894,8 +1894,8 @@ class Isolate extends ServiceObjectOwner implements M.Isolate { return invokeRpc('setName', {'name': newName}); } - Future setIsolatePauseMode(String mode) { - return invokeRpc('setIsolatePauseMode', {'exceptionPauseMode': mode}); + Future setExceptionPauseMode(String mode) { + return invokeRpc('setExceptionPauseMode', {'mode': mode}); } Future getStack({int limit}) { diff --git a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart index 5fe3ff70bfd..6f53fb7d0b9 100644 --- a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart +++ b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart @@ -11,8 +11,8 @@ var tests = [ (VM vm) async { final result = await vm.invokeRpcNoUpgrade('getVersion', {}); expect(result['type'], equals('Version')); - expect(result['major'], equals(4)); - expect(result['minor'], equals(0)); + expect(result['major'], equals(3)); + expect(result['minor'], equals(62)); expect(result['_privateMajor'], equals(0)); expect(result['_privateMinor'], equals(0)); }, diff --git a/runtime/observatory_2/tests/service_2/pause_on_exceptions_test.dart b/runtime/observatory_2/tests/service_2/pause_on_exceptions_test.dart index 1b4da9836a2..fa506c92f16 100644 --- a/runtime/observatory_2/tests/service_2/pause_on_exceptions_test.dart +++ b/runtime/observatory_2/tests/service_2/pause_on_exceptions_test.dart @@ -52,8 +52,8 @@ var tests = [ bool shouldBeCaught) async { print("Evaluating $expression with pause on $pauseMode exception"); - expect( - (await isolate.setIsolatePauseMode(pauseMode)) is DartError, isFalse); + expect((await isolate.setExceptionPauseMode(pauseMode)) is DartError, + isFalse); var t; if (shouldPause) { diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc index 7edada71f48..f260ecdf611 100644 --- a/runtime/vm/object_service.cc +++ b/runtime/vm/object_service.cc @@ -1124,8 +1124,8 @@ void Instance::PrintSharedInstanceJSON(JSONObject* jsobj, if (!field.is_static()) { field_value = GetField(field); JSONObject jsfield(&jsarr); + jsfield.AddProperty("type", "BoundField"); jsfield.AddProperty("decl", field); - jsfield.AddProperty("name", field.UserVisibleNameCString()); 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 { JSONObject jsobj(stream); PrintSharedInstanceJSON(&jsobj, ref); - jsobj.AddProperty("kind", "RecordType"); + jsobj.AddProperty("kind", "_RecordType"); if (ref) { return; } @@ -1630,7 +1630,7 @@ void Closure::PrintJSONImpl(JSONStream* stream, bool ref) const { void Record::PrintJSONImpl(JSONStream* stream, bool ref) const { JSONObject jsobj(stream); PrintSharedInstanceJSON(&jsobj, ref); - jsobj.AddProperty("kind", "Record"); + jsobj.AddProperty("kind", "_Record"); if (ref) { return; } diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc index 44105b12a42..52903dc74da 100644 --- a/runtime/vm/profiler_service.cc +++ b/runtime/vm/profiler_service.cc @@ -1559,6 +1559,9 @@ void Profile::PrintHeaderJSON(JSONObject* obj) { obj->AddProperty("maxStackDepth", static_cast(FLAG_max_profile_depth)); 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("timeExtentMicros", GetTimeSpan()); obj->AddProperty64("pid", pid); diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index 32d798484c6..8e552ebcc15 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -2321,7 +2321,6 @@ static void PrintInboundReferences(Thread* thread, (slot_offset.Value() - Array::element_offset(0)) / Array::kBytesPerElement; jselement.AddProperty("parentListIndex", element_index); - jselement.AddProperty("parentField", element_index); } else if (source.IsRecord()) { AddParentFieldToResponseBasedOnRecord(thread, &field_names, &name, jselement, Record::Cast(source), @@ -2352,7 +2351,6 @@ static void PrintInboundReferences(Thread* thread, (slot_offset.Value() - Context::variable_offset(0)) / Context::kBytesPerElement; jselement.AddProperty("parentListIndex", element_index); - jselement.AddProperty("parentField", element_index); } else { jselement.AddProperty("_parentWordOffset", slot_offset.Value()); } @@ -2447,7 +2445,6 @@ static void PrintRetainingPath(Thread* thread, (slot_offset.Value() - Array::element_offset(0)) / Array::kBytesPerElement; jselement.AddProperty("parentListIndex", element_index); - jselement.AddProperty("parentField", element_index); } else if (element.IsRecord()) { AddParentFieldToResponseBasedOnRecord(thread, &field_names, &name, jselement, Record::Cast(element), @@ -2494,7 +2491,6 @@ static void PrintRetainingPath(Thread* thread, (slot_offset.Value() - Context::variable_offset(0)) / Context::kBytesPerElement; jselement.AddProperty("parentListIndex", element_index); - jselement.AddProperty("parentField", element_index); } else { jselement.AddProperty("_parentWordOffset", slot_offset.Value()); } @@ -5419,6 +5415,27 @@ static const MethodParameter* const set_exception_pause_mode_params[] = { 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[] = { ISOLATE_PARAMETER, new EnumParameter("exceptionPauseMode", false, exception_pause_mode_names), @@ -5872,6 +5889,8 @@ static const ServiceMethodDescriptor service_methods_[] = { evaluate_compiled_expression_params }, { "setBreakpointState", SetBreakpointState, set_breakpoint_state_params }, + { "setExceptionPauseMode", SetExceptionPauseMode, + set_exception_pause_mode_params }, { "setIsolatePauseMode", SetIsolatePauseMode, set_isolate_pause_mode_params }, { "setFlag", SetFlag, diff --git a/runtime/vm/service.h b/runtime/vm/service.h index d0aa66991cd..b596e14199c 100644 --- a/runtime/vm/service.h +++ b/runtime/vm/service.h @@ -16,8 +16,8 @@ namespace dart { -#define SERVICE_PROTOCOL_MAJOR_VERSION 4 -#define SERVICE_PROTOCOL_MINOR_VERSION 0 +#define SERVICE_PROTOCOL_MAJOR_VERSION 3 +#define SERVICE_PROTOCOL_MINOR_VERSION 62 class Array; class EmbedderServiceHandler; diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md index 034cccc47c9..ded9453d213 100644 --- a/runtime/vm/service/service.md +++ b/runtime/vm/service/service.md @@ -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] -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. 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) - [resume](#resume) - [setBreakpointState](#setbreakpointstate) + - [setExceptionPauseMode](#setexceptionpausemode) - [setFlag](#setflag) - [setLibraryDebuggable](#setlibrarydebuggable) - [setName](#setname) @@ -120,7 +121,7 @@ The Service Protocol uses [JSON-RPC 2.0][]. - [NativeFunction](#nativefunction) - [Null](#null) - [Object](#object) - - [Parameter](#parameter) + - [Parameter](#parameter)[ - [PortList](#portlist) - [ReloadReport](#reloadreport) - [Response](#response) @@ -143,7 +144,7 @@ The Service Protocol uses [JSON-RPC 2.0][]. - [TimelineFlags](#timelineflags) - [Timestamp](#timestamp) - [TypeArguments](#typearguments) - - [TypeParameters](#typeparameters) + - [TypeParameters](#typeparameters)[ - [UnresolvedSourceLocation](#unresolvedsourcelocation) - [UriList](#urilist) - [Version](#version) @@ -1383,6 +1384,25 @@ The returned [Breakpoint](#breakpoint) is the updated breakpoint with its new values. 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 @@ -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 _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 @@ -1685,12 +1708,7 @@ class AllocationProfile extends Response { ``` 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; - string|int name; @Instance|Sentinel value; } ``` @@ -1962,6 +1980,12 @@ class CpuSamples extends Response { // The number of samples returned. 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 // collected. int timeOriginMicros; @@ -1998,6 +2022,12 @@ class CpuSamplesEvent { // The number of samples returned. 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 // collected. int timeOriginMicros; @@ -3103,9 +3133,6 @@ enum InstanceKind { Float32x4List, Float64x2List, - // An instance of the Dart class Record. - Record, - // An instance of the Dart class StackTrace. StackTrace, @@ -3137,9 +3164,6 @@ enum InstanceKind { // An instance of the Dart class FunctionType. FunctionType, - // An instance of the Dart class RecordType. - RecordType, - // An instance of the Dart class BoundedType. BoundedType, @@ -3320,21 +3344,12 @@ class InboundReference { // The object holding the inbound reference. @Object source; - // If source is a List, parentListIndex is the index of the inbound reference (deprecated). - // - // Note: this property is deprecated and will be replaced by `parentField`. + // If source is a List, parentListIndex is the index of the inbound reference. int parentListIndex [optional]; - // If `source` is a `List`, `parentField` is the index of the inbound - // reference. - // If `source` is a record, `parentField` is the field name of the 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`. - @Field|string|int parentField [optional]; + // If source is a field of an object, parentField is the field containing the + // inbound reference. + @Field parentField [optional]; } ``` @@ -3746,9 +3761,7 @@ class RetainingObject { @Object value; // If `value` is a List, `parentListIndex` is the index where the previous - // object on the retaining path is located (deprecated). - // - // Note: this property is deprecated and will be replaced by `parentField`. + // object on the retaining path is located. int parentListIndex [optional]; // 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 // 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.61 | Added `isolateGroupId` property to `@Isolate` and `Isolate`. 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