From f5080bedb38c77bd99b5caa0bc012007ab7158e3 Mon Sep 17 00:00:00 2001 From: Derek Xu Date: Tue, 11 Jul 2023 18:41:04 +0000 Subject: [PATCH] [VM/Debugger] Fix behaviour of ActivationFrame::EvaluateCompiledExpression when paused inside a closure TEST=pkg/vm_service/test/evaluate_inside_closures_test.dart, pkg tryjob Fixes: https://github.com/dart-lang/sdk/issues/52430 Change-Id: I72b755d31614c7c56c504130656c3668d8b7e72b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313001 Commit-Queue: Derek Xu Reviewed-by: Ben Konyi --- .../test/evaluate_inside_closures_test.dart | 92 +++++++++++++++++++ runtime/vm/debugger.cc | 5 +- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 pkg/vm_service/test/evaluate_inside_closures_test.dart diff --git a/pkg/vm_service/test/evaluate_inside_closures_test.dart b/pkg/vm_service/test/evaluate_inside_closures_test.dart new file mode 100644 index 000000000000..434775a8fb3c --- /dev/null +++ b/pkg/vm_service/test/evaluate_inside_closures_test.dart @@ -0,0 +1,92 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Regression test for https://dartbug.com/52430. + +import 'dart:developer'; + +import 'package:test/test.dart'; +import 'package:vm_service/vm_service.dart'; + +import 'common/service_test_common.dart'; +import 'common/test_helper.dart'; + +class C { + static int staticField = 12; + int instanceField = 34; + + static void staticMethod() { + ((int x) { + debugger(); + })(56); + } + + void instanceMethod() { + ((int y) { + debugger(); + })(78); + } +} + +testMain() { + C c = C(); + C.staticMethod(); + c.instanceMethod(); +} + +final tests = [ + hasStoppedAtBreakpoint, + stoppedAtLine(21), + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + + final xRef = + await service.evaluateInFrame(isolateId, 0, 'x') as InstanceRef; + expect(xRef.valueAsString, '56'); + + InstanceRef staticFieldRef = await service.evaluateInFrame( + isolateId, 0, 'staticField += 1') as InstanceRef; + expect(staticFieldRef.valueAsString, '13'); + staticFieldRef = await service.evaluateInFrame(isolateId, 0, 'staticField') + as InstanceRef; + expect(staticFieldRef.valueAsString, '13'); + + // Evaluating 'instanceField' should fail since we are paused in the context + // of a static method. + try { + await service.evaluateInFrame(isolateId, 0, 'instanceField'); + fail('Expected RPCError'); + } catch (e) { + final rpcError = e as RPCError; + expect(rpcError.code, RPCErrorKind.kExpressionCompilationError.code); + } + }, + resumeIsolate, + stoppedAtLine(27), + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + + final yRef = + await service.evaluateInFrame(isolateId, 0, 'y') as InstanceRef; + expect(yRef.valueAsString, '78'); + + InstanceRef staticFieldRef = await service.evaluateInFrame( + isolateId, 0, 'staticField += 1') as InstanceRef; + expect(staticFieldRef.valueAsString, '14'); + staticFieldRef = await service.evaluateInFrame(isolateId, 0, 'staticField') + as InstanceRef; + expect(staticFieldRef.valueAsString, '14'); + + InstanceRef instanceFieldRef = await service.evaluateInFrame( + isolateId, 0, 'instanceField += 1') as InstanceRef; + expect(instanceFieldRef.valueAsString, '35'); + instanceFieldRef = await service.evaluateInFrame( + isolateId, 0, 'instanceField') as InstanceRef; + expect(instanceFieldRef.valueAsString, '35'); + } +]; + +main([args = const []]) async => + runIsolateTests(args, tests, 'evaluate_inside_closures_test.dart', + testeeConcurrent: testMain); diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index 5b7c00a2f733..64d965ecb76f 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -1055,7 +1055,10 @@ ObjectPtr ActivationFrame::EvaluateCompiledExpression( const Array& type_definitions, const Array& arguments, const TypeArguments& type_arguments) { - if (function().is_static()) { + if (function().IsClosureFunction()) { + return Library::Handle(Library()).EvaluateCompiledExpression( + kernel_buffer, type_definitions, arguments, type_arguments); + } else if (function().is_static()) { const Class& cls = Class::Handle(function().Owner()); return cls.EvaluateCompiledExpression(kernel_buffer, type_definitions, arguments, type_arguments);