From 3bef6cf639610ea542d7eb64b37d84289ab2899e Mon Sep 17 00:00:00 2001 From: Alexander Markov Date: Wed, 6 Jan 2021 18:12:51 +0000 Subject: [PATCH] [vm/aot] Attach unboxing info to unreachable members Unreachable members could be used as interface targets of dispatch table calls, so they should have correct unboxing metadata. This change fixes attaching unboxing info to such members. TEST=runtime/tests/vm/dart/regress_44563_test.dart Fixes https://github.com/dart-lang/sdk/issues/44563 Change-Id: I5da6a8d07048904eb94b05bfba11bdf72d655e12 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/177621 Reviewed-by: Aske Simon Christensen Reviewed-by: Martin Kustermann Commit-Queue: Alexander Markov --- .../type_flow/transformer.dart | 60 +++++++++---------- runtime/tests/vm/dart/regress_44563_test.dart | 31 ++++++++++ .../tests/vm/dart_2/regress_44563_test.dart | 31 ++++++++++ 3 files changed, 91 insertions(+), 31 deletions(-) create mode 100644 runtime/tests/vm/dart/regress_44563_test.dart create mode 100644 runtime/tests/vm/dart_2/regress_44563_test.dart diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart index 9f4dfd2eb528..a19269402e32 100644 --- a/pkg/vm/lib/transformations/type_flow/transformer.dart +++ b/pkg/vm/lib/transformations/type_flow/transformer.dart @@ -313,13 +313,6 @@ class AnnotateKernel extends RecursiveVisitor { if (_typeFlowAnalysis.isMemberUsed(member)) { if (member is Field) { _setInferredType(member, _typeFlowAnalysis.fieldType(member)); - - final unboxingInfoMetadata = - _unboxingInfo.getUnboxingInfoOfMember(member); - if (unboxingInfoMetadata != null && - !unboxingInfoMetadata.isFullyBoxed) { - _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata; - } } else { Args argTypes = _typeFlowAnalysis.argumentTypes(member); final uncheckedParameters = @@ -350,36 +343,41 @@ class AnnotateKernel extends RecursiveVisitor { skipCheck: uncheckedParameters.contains(param)); } - final unboxingInfoMetadata = - _unboxingInfo.getUnboxingInfoOfMember(member); - if (unboxingInfoMetadata != null && - !unboxingInfoMetadata.isFullyBoxed) { - _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata; - } - // TODO(alexmarkov): figure out how to pass receiver type. } - } else if (!member.isAbstract && - !fieldMorpher.isExtraMemberWithReachableBody(member)) { - _setUnreachable(member); - } else if (member is! Field) { + final unboxingInfoMetadata = _unboxingInfo.getUnboxingInfoOfMember(member); - if (unboxingInfoMetadata != null) { - // Check for partitions that only have abstract methods should be marked as boxed. - if (unboxingInfoMetadata.returnInfo == - UnboxingInfoMetadata.kUnboxingCandidate) { - unboxingInfoMetadata.returnInfo = UnboxingInfoMetadata.kBoxed; - } - for (int i = 0; i < unboxingInfoMetadata.unboxedArgsInfo.length; i++) { - if (unboxingInfoMetadata.unboxedArgsInfo[i] == + if (unboxingInfoMetadata != null && !unboxingInfoMetadata.isFullyBoxed) { + _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata; + } + } else { + if (!member.isAbstract && + !fieldMorpher.isExtraMemberWithReachableBody(member)) { + _setUnreachable(member); + } + + if (member is! Field) { + final unboxingInfoMetadata = + _unboxingInfo.getUnboxingInfoOfMember(member); + if (unboxingInfoMetadata != null) { + // Check for partitions that only have abstract methods should be marked as boxed. + if (unboxingInfoMetadata.returnInfo == UnboxingInfoMetadata.kUnboxingCandidate) { - unboxingInfoMetadata.unboxedArgsInfo[i] = - UnboxingInfoMetadata.kBoxed; + unboxingInfoMetadata.returnInfo = UnboxingInfoMetadata.kBoxed; + } + for (int i = 0; + i < unboxingInfoMetadata.unboxedArgsInfo.length; + i++) { + if (unboxingInfoMetadata.unboxedArgsInfo[i] == + UnboxingInfoMetadata.kUnboxingCandidate) { + unboxingInfoMetadata.unboxedArgsInfo[i] = + UnboxingInfoMetadata.kBoxed; + } + } + if (!unboxingInfoMetadata.isFullyBoxed) { + _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata; } - } - if (!unboxingInfoMetadata.isFullyBoxed) { - _unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata; } } } diff --git a/runtime/tests/vm/dart/regress_44563_test.dart b/runtime/tests/vm/dart/regress_44563_test.dart new file mode 100644 index 000000000000..6b1baa633658 --- /dev/null +++ b/runtime/tests/vm/dart/regress_44563_test.dart @@ -0,0 +1,31 @@ +// 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. + +// Verifies that unboxing info is attached to a member with unreachable body, +// which is still used as an interface target. +// Regression test for https://github.com/dart-lang/sdk/issues/44563. + +import 'package:expect/expect.dart'; + +class BaseClass { + int get value => 0; +} + +class Class1 extends BaseClass { + @pragma('vm:never-inline') + int get value => 1; +} + +class Class2 extends BaseClass { + @pragma('vm:never-inline') + int get value => 2; +} + +bool nonConstantCondition = int.parse("1") == 1; + +void main() { + BaseClass obj = BaseClass(); + obj = nonConstantCondition ? Class1() : Class2(); + Expect.equals(1, obj.value); +} diff --git a/runtime/tests/vm/dart_2/regress_44563_test.dart b/runtime/tests/vm/dart_2/regress_44563_test.dart new file mode 100644 index 000000000000..6b1baa633658 --- /dev/null +++ b/runtime/tests/vm/dart_2/regress_44563_test.dart @@ -0,0 +1,31 @@ +// 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. + +// Verifies that unboxing info is attached to a member with unreachable body, +// which is still used as an interface target. +// Regression test for https://github.com/dart-lang/sdk/issues/44563. + +import 'package:expect/expect.dart'; + +class BaseClass { + int get value => 0; +} + +class Class1 extends BaseClass { + @pragma('vm:never-inline') + int get value => 1; +} + +class Class2 extends BaseClass { + @pragma('vm:never-inline') + int get value => 2; +} + +bool nonConstantCondition = int.parse("1") == 1; + +void main() { + BaseClass obj = BaseClass(); + obj = nonConstantCondition ? Class1() : Class2(); + Expect.equals(1, obj.value); +}