diff --git a/pkg/dds/lib/src/dap/isolate_manager.dart b/pkg/dds/lib/src/dap/isolate_manager.dart index fd2d342e353..688a7ace08b 100644 --- a/pkg/dds/lib/src/dap/isolate_manager.dart +++ b/pkg/dds/lib/src/dap/isolate_manager.dart @@ -581,7 +581,10 @@ class IsolateManager { return; } - await service.setExceptionPauseMode(isolate.id!, _exceptionPauseMode); + await service.setIsolatePauseMode( + isolate.id!, + exceptionPauseMode: _exceptionPauseMode, + ); } /// Calls setLibraryDebuggable for all libraries in the given isolate based diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml index bafc2dc3d03..e575eaec51c 100644 --- a/pkg/dds/pubspec.yaml +++ b/pkg/dds/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: shelf_web_socket: ^1.0.0 sse: ^4.0.0 stream_channel: ^2.0.0 - vm_service: ^7.2.0 + vm_service: ^7.5.0 web_socket_channel: ^2.0.0 dev_dependencies: diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md index 50d973c50bd..760c9d9b99c 100644 --- a/pkg/vm_service/CHANGELOG.md +++ b/pkg/vm_service/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 7.5.0 +- Update to version `3.53` of the spec. +- Added `setIsolatePauseMode` RPC. +- Deprecated `setExceptionPauseMode` in favor of `setIsolatePauseMode`. + ## 7.4.0 - Update to version `3.52` of the spec. - Added `lookupResolvedPackageUris` and `lookupPackageUris` RPCs and `UriList` diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore index 817e983a10e..a54ba8c0584 100644 --- a/pkg/vm_service/java/.gitignore +++ b/pkg/vm_service/java/.gitignore @@ -36,6 +36,7 @@ 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 src/org/dartlang/vm/service/consumer/SetNameConsumer.java src/org/dartlang/vm/service/consumer/SetTraceClassAllocationConsumer.java diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties index 8ae699842a4..b8e9261ad9e 100644 --- a/pkg/vm_service/java/version.properties +++ b/pkg/vm_service/java/version.properties @@ -1 +1 @@ -version=3.52 +version=3.53 diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart index 51958bd5b4f..278e6cfffd4 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 = '3.52.0'; +const String vmServiceVersion = '3.53.0'; /// @optional const String optional = 'optional'; @@ -236,6 +236,7 @@ Map> _methodReturnTypes = { 'resume': const ['Success'], 'setBreakpointState': const ['Breakpoint'], 'setExceptionPauseMode': const ['Success'], + 'setIsolatePauseMode': const ['Success'], 'setFlag': const ['Success', 'Error'], 'setLibraryDebuggable': const ['Success'], 'setName': const ['Success'], @@ -1078,9 +1079,34 @@ abstract class VmServiceInterface { /// /// 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 + /// 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. + Future setIsolatePauseMode(String isolateId, + {/*ExceptionPauseMode*/ String? exceptionPauseMode, + bool? shouldPauseOnExit}); + /// The `setFlag` RPC is used to set a VM flag at runtime. Returns an error if /// the named flag does not exist, the flag may not be set at runtime, or the /// value is of the wrong type for the flag. @@ -1101,6 +1127,7 @@ abstract class VmServiceInterface { /// provided value. If set to false when the profiler is already running, the /// profiler will be stopped but may not free its sample buffer depending on /// platform limitations. + /// - Isolate pause settings will only be applied to newly spawned isolates. /// /// See [Success]. /// @@ -1549,11 +1576,19 @@ class VmServerConnection { ); 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'], + exceptionPauseMode: params['exceptionPauseMode'], + shouldPauseOnExit: params['shouldPauseOnExit'], + ); + break; case 'setFlag': response = await _serviceImplementation.setFlag( params!['name'], @@ -2081,11 +2116,23 @@ 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, + bool? shouldPauseOnExit}) => + _call('setIsolatePauseMode', { + 'isolateId': isolateId, + if (exceptionPauseMode != null) + 'exceptionPauseMode': exceptionPauseMode, + if (shouldPauseOnExit != null) 'shouldPauseOnExit': shouldPauseOnExit, + }); + @override Future setFlag(String name, String value) => _call('setFlag', {'name': name, 'value': value}); diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml index 29845923571..8bd5ed5b4a3 100644 --- a/pkg/vm_service/pubspec.yaml +++ b/pkg/vm_service/pubspec.yaml @@ -3,7 +3,7 @@ description: >- A library to communicate with a service implementing the Dart VM service protocol. -version: 7.4.0 +version: 7.5.0 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart index 585722f1015..8bf30b88873 100644 --- a/pkg/vm_service/test/common/test_helper.dart +++ b/pkg/vm_service/test/common/test_helper.dart @@ -277,7 +277,6 @@ class _ServiceTesterRunner { vm = await vmServiceConnectUri(serviceWebsocketAddress); print('Done loading VM'); isolate = await getFirstIsolate(vm); - print('Got first isolate'); }); }); @@ -335,14 +334,12 @@ class _ServiceTesterRunner { if (event.kind == EventKind.kIsolateRunnable) { print(event.isolate!.name); vm = await service.getVM(); - //assert(vmIsolates.isNotEmpty); await subscription.cancel(); await service.streamCancel(EventStreams.kIsolate); completer!.complete(event.isolate!); completer = null; } }); - await service.streamListen(EventStreams.kIsolate); // The isolate may have started before we subscribed. 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/pkg/vm_service/test/pause_on_exceptions_test.dart b/pkg/vm_service/test/pause_on_exceptions_test.dart new file mode 100644 index 00000000000..9da7dfcbdfa --- /dev/null +++ b/pkg/vm_service/test/pause_on_exceptions_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"); + + await service.setIsolatePauseMode(isolate.id!, + exceptionPauseMode: 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/pkg/vm_service/test/should_pause_on_exit_test.dart b/pkg/vm_service/test/should_pause_on_exit_test.dart new file mode 100644 index 00000000000..575530c90da --- /dev/null +++ b/pkg/vm_service/test/should_pause_on_exit_test.dart @@ -0,0 +1,51 @@ +// 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'; + +void testMain() { + print('Hello world!'); +} + +Future shouldPauseOnExit(VmService service, IsolateRef isolateRef) async { + final isolate = await service.getIsolate(isolateRef.id!); + return isolate.pauseOnExit!; +} + +final tests = [ + (VmService service, IsolateRef isolateRef) async { + await service.setIsolatePauseMode(isolateRef.id!, shouldPauseOnExit: false); + expect(await shouldPauseOnExit(service, isolateRef), false); + final completer = Completer(); + + final stream = service.onDebugEvent; + final subscription = stream.listen((Event event) { + if (event.kind == EventKind.kPauseExit) { + completer.complete(); + } + }); + await service.streamListen(EventStreams.kDebug); + + await service.setIsolatePauseMode(isolateRef.id!, shouldPauseOnExit: true); + expect(await shouldPauseOnExit(service, isolateRef), true); + await service.resume(isolateRef.id!); + await completer.future; + await service.resume(isolateRef.id!); + await subscription.cancel(); + }, +]; + +void main([args = const []]) => runIsolateTests( + args, + tests, + 'should_pause_on_exit_test.dart', + pause_on_start: true, + pause_on_exit: true, + testeeConcurrent: testMain, + ); diff --git a/pkg/vm_service/tool/common/parser.dart b/pkg/vm_service/tool/common/parser.dart index 08d3709f2a7..233320ae677 100644 --- a/pkg/vm_service/tool/common/parser.dart +++ b/pkg/vm_service/tool/common/parser.dart @@ -167,6 +167,23 @@ abstract class Parser { .trim(); } + String? consumeString() { + StringBuffer buf = StringBuffer(); + String startQuotation = advance()!.text!; + if (startQuotation != '"' && startQuotation != "'") { + return null; + } + while (peek()!.text != startQuotation) { + Token t = advance()!; + if (t.text == null) { + throw FormatException('Reached EOF'); + } + buf.write('${t.text} '); + } + advance(); + return buf.toString().trim(); + } + void validate(bool result, String message) { if (!result) throw 'expected ${message}'; } diff --git a/pkg/vm_service/tool/dart/generate_dart.dart b/pkg/vm_service/tool/dart/generate_dart.dart index 844b1ff4fac..4f2eb167839 100644 --- a/pkg/vm_service/tool/dart/generate_dart.dart +++ b/pkg/vm_service/tool/dart/generate_dart.dart @@ -725,6 +725,9 @@ abstract class VmServiceInterface { } return result; }; + if (m.deprecated) { + gen.writeln("// ignore: deprecated_member_use_from_same_package"); + } gen.write("response = await _serviceImplementation.${m.name}("); // Positional args m.args.where((arg) => !arg.optional).forEach((MethodArg arg) { @@ -1130,6 +1133,8 @@ class Method extends Member { final String? docs; MemberType returnType = MemberType(); + bool get deprecated => deprecationMessage != null; + String? deprecationMessage; List args = []; Method(this.name, String definition, [this.docs]) { @@ -1196,6 +1201,9 @@ class Method extends Member { } if (_docs.isNotEmpty) gen.writeDocs(_docs); } + if (deprecated) { + gen.writeln("@Deprecated('$deprecationMessage')"); + } if (withOverrides) gen.writeln('@override'); gen.write('Future<${returnType.name}> ${name}('); bool startedOptional = false; @@ -2128,7 +2136,12 @@ class MethodParser extends Parser { void parseInto(Method method) { // method is return type, name, (, args ) // args is type name, [optional], comma - + if (peek()?.text?.startsWith('@deprecated') ?? false) { + advance(); + expect('('); + method.deprecationMessage = consumeString()!; + expect(')'); + } method.returnType.parse(this, isReturnType: true); Token t = expectName(); diff --git a/pkg/vm_service/tool/java/generate_java.dart b/pkg/vm_service/tool/java/generate_java.dart index 9ef243d14b0..c80a481a897 100644 --- a/pkg/vm_service/tool/java/generate_java.dart +++ b/pkg/vm_service/tool/java/generate_java.dart @@ -496,6 +496,7 @@ class Method extends Member { final String? docs; MemberType returnType = MemberType(); + bool deprecated = false; List args = []; Method(this.name, String definition, [this.docs]) { @@ -606,7 +607,7 @@ class Method extends Member { } } writer.addLine('request("$name", params, consumer);'); - }, javadoc: javadoc.toString()); + }, javadoc: javadoc.toString(), isDeprecated: deprecated); } void _parse(Token? token) { @@ -647,6 +648,13 @@ class MethodParser extends Parser { // method is return type, name, (, args ) // args is type name, [optional], comma + if (peek()?.text?.startsWith('@deprecated') ?? false) { + advance(); + expect('('); + consumeString(); + expect(')'); + method.deprecated = true; + } method.returnType.parse(this); Token t = expectName(); diff --git a/pkg/vm_service/tool/java/src_gen_java.dart b/pkg/vm_service/tool/java/src_gen_java.dart index b67c2037ef8..a2e62e55ed0 100644 --- a/pkg/vm_service/tool/java/src_gen_java.dart +++ b/pkg/vm_service/tool/java/src_gen_java.dart @@ -214,6 +214,7 @@ class TypeWriter { String? modifiers = 'public', String? returnType = 'void', bool isOverride = false, + bool isDeprecated = false, }) { var methodDecl = StringBuffer(); if (javadoc != null && javadoc.isNotEmpty) { @@ -223,6 +224,9 @@ class TypeWriter { .forEach((line) => methodDecl.writeln(' * $line'.trimRight())); methodDecl.writeln(' */'); } + if (isDeprecated) { + methodDecl.writeln(' @Deprecated'); + } if (isOverride) { methodDecl.writeln(' @Override'); } diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart index 4ad1d938d61..7b1f2751d3f 100644 --- a/runtime/observatory/tests/service/get_version_rpc_test.dart +++ b/runtime/observatory/tests/service/get_version_rpc_test.dart @@ -12,7 +12,7 @@ var tests = [ final result = await vm.invokeRpcNoUpgrade('getVersion', {}); expect(result['type'], 'Version'); expect(result['major'], 3); - expect(result['minor'], 52); + expect(result['minor'], 53); expect(result['_privateMajor'], 0); expect(result['_privateMinor'], 0); }, 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 12ffc1c668b..e9c87c9a855 100644 --- a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart +++ b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart @@ -12,7 +12,7 @@ var tests = [ final result = await vm.invokeRpcNoUpgrade('getVersion', {}); expect(result['type'], equals('Version')); expect(result['major'], equals(3)); - expect(result['minor'], equals(52)); + expect(result['minor'], equals(53)); expect(result['_privateMajor'], equals(0)); expect(result['_privateMinor'], equals(0)); }, diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index b70dea0689d..77767cbaa27 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -5164,6 +5164,44 @@ static void SetExceptionPauseMode(Thread* thread, JSONStream* js) { PrintSuccess(js); } +static const MethodParameter* const set_isolate_pause_mode_params[] = { + ISOLATE_PARAMETER, + new EnumParameter("exceptionPauseMode", false, exception_pause_mode_names), + new BoolParameter("shouldPauseOnExit", false), + nullptr, +}; + +static void SetIsolatePauseMode(Thread* thread, JSONStream* js) { + bool state_changed = false; + const char* exception_pause_mode = js->LookupParam("exceptionPauseMode"); + if (exception_pause_mode != nullptr) { + Dart_ExceptionPauseInfo info = + EnumMapper(exception_pause_mode, exception_pause_mode_names, + exception_pause_mode_values); + if (info == kInvalidExceptionPauseInfo) { + PrintInvalidParamError(js, "exceptionPauseMode"); + return; + } + Isolate* isolate = thread->isolate(); + isolate->debugger()->SetExceptionPauseInfo(info); + state_changed = true; + } + + const char* pause_isolate_on_exit = js->LookupParam("shouldPauseOnExit"); + if (pause_isolate_on_exit != nullptr) { + bool enable = BoolParameter::Parse(pause_isolate_on_exit, false); + thread->isolate()->message_handler()->set_should_pause_on_exit(enable); + state_changed = true; + } + + if (state_changed && Service::debug_stream.enabled()) { + ServiceEvent event(thread->isolate(), + ServiceEvent::kDebuggerSettingsUpdate); + Service::HandleEvent(&event); + } + PrintSuccess(js); +} + static const MethodParameter* const set_breakpoint_state_params[] = { ISOLATE_PARAMETER, new IdParameter("breakpointId", true), @@ -5580,6 +5618,8 @@ static const ServiceMethodDescriptor service_methods_[] = { set_breakpoint_state_params }, { "setExceptionPauseMode", SetExceptionPauseMode, set_exception_pause_mode_params }, + { "setIsolatePauseMode", SetIsolatePauseMode, + set_isolate_pause_mode_params }, { "setFlag", SetFlag, set_flags_params }, { "setLibraryDebuggable", SetLibraryDebuggable, diff --git a/runtime/vm/service.h b/runtime/vm/service.h index f51eb1040e6..7910d790cc7 100644 --- a/runtime/vm/service.h +++ b/runtime/vm/service.h @@ -15,7 +15,7 @@ namespace dart { #define SERVICE_PROTOCOL_MAJOR_VERSION 3 -#define SERVICE_PROTOCOL_MINOR_VERSION 52 +#define SERVICE_PROTOCOL_MINOR_VERSION 53 class Array; class EmbedderServiceHandler; diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md index ba4add137e6..0865d158c85 100644 --- a/runtime/vm/service/service.md +++ b/runtime/vm/service/service.md @@ -1,8 +1,8 @@ -# Dart VM Service Protocol 3.52 +# Dart VM Service Protocol 3.53 > Please post feedback to the [observatory-discuss group][discuss-list] -This document describes of _version 3.52_ of the Dart VM Service Protocol. This +This document describes of _version 3.53_ 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. @@ -1378,6 +1378,7 @@ See [Breakpoint](#breakpoint). ### setExceptionPauseMode ``` +@deprecated('Use setIsolatePauseMode instead') Success|Sentinel setExceptionPauseMode(string isolateId, ExceptionPauseMode mode) ``` @@ -1394,6 +1395,31 @@ All | Pause isolate on all thrown exceptions If _isolateId_ refers to an isolate which has exited, then the _Collected_ [Sentinel](#sentinel) is returned. +### setIsolatePauseMode + +``` +Success|Sentinel setIsolatePauseMode(string isolateId, + ExceptionPauseMode exceptionPauseMode [optional], + bool shouldPauseOnExit [optional]) +``` + +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 +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. + ### setFlag ``` @@ -1420,6 +1446,7 @@ Notes: provided value. If set to false when the profiler is already running, the profiler will be stopped but may not free its sample buffer depending on platform limitations. + * Isolate pause settings will only be applied to newly spawned isolates. See [Success](#success). @@ -4235,4 +4262,5 @@ version | comments 3.50 | Added `returnType`, `parameters`, and `typeParameters` to `@Instance`, and `implicit` to `@Function`. Added `Parameter` type. 3.51 | Added optional `reportLines` parameter to `getSourceReport` RPC. 3.52 | Added `lookupResolvedPackageUris` and `lookupPackageUris` RPCs and `UriList` type. +3.53 | Added `setIsolatePauseMode` RPC. [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss