[vm,aot] Fix unboxing info (including calling conventions) on unreachable fields
For some reason unboxing information was not generated for unreachable fields. However, unreachable field can be used as an interface target, and unboxing info contains a flag indicating if register calling convention should be used which affects how the call via this field as an interface target is going to be performed. So it is incorrect to omit such unboxing info and this change fixes this bug. TEST=vm/dart/regress_b_450678575_test Bug: b/450678575 Change-Id: Ic1f299d9c0b09005c8bbfd95d1a409c113630263 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/454681 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
committed by
Commit Queue
parent
631fb95ef1
commit
72bd9baa54
@@ -731,24 +731,22 @@ class AnnotateKernel extends RecursiveVisitor {
|
||||
_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 == UnboxingType.kUnknown) {
|
||||
unboxingInfoMetadata.returnInfo = UnboxingType.kBoxed;
|
||||
}
|
||||
for (int i = 0; i < unboxingInfoMetadata.argsInfo.length; i++) {
|
||||
if (unboxingInfoMetadata.argsInfo[i] == UnboxingType.kUnknown) {
|
||||
unboxingInfoMetadata.argsInfo[i] = UnboxingType.kBoxed;
|
||||
}
|
||||
}
|
||||
if (!unboxingInfoMetadata.isTrivial) {
|
||||
_unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata;
|
||||
final unboxingInfoMetadata = _unboxingInfo.getUnboxingInfoOfMember(
|
||||
member,
|
||||
);
|
||||
if (unboxingInfoMetadata != null) {
|
||||
// Check for partitions that only have abstract methods should be marked as boxed.
|
||||
if (unboxingInfoMetadata.returnInfo == UnboxingType.kUnknown) {
|
||||
unboxingInfoMetadata.returnInfo = UnboxingType.kBoxed;
|
||||
}
|
||||
for (int i = 0; i < unboxingInfoMetadata.argsInfo.length; i++) {
|
||||
if (unboxingInfoMetadata.argsInfo[i] == UnboxingType.kUnknown) {
|
||||
unboxingInfoMetadata.argsInfo[i] = UnboxingType.kBoxed;
|
||||
}
|
||||
}
|
||||
if (!unboxingInfoMetadata.isTrivial) {
|
||||
_unboxingInfoMetadata.mapping[member] = unboxingInfoMetadata;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ abstract class Foo extends core::Object {
|
||||
|
||||
[@vm.unreachable.metadata=]
|
||||
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:1]
|
||||
[@vm.unboxing-info.metadata=[!regcc]]
|
||||
@#C3
|
||||
late final field core::int hashCode = throw "Attempt to execute code removed by Dart AOT compiler (TFA)";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2025, 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 b/450678575.
|
||||
//
|
||||
// Verifies that compiler uses correct calling conventions (!regcc)
|
||||
// when using unreachable field as an interface target.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
bool opaqueTrue = int.parse('1') == 1;
|
||||
|
||||
int listener = -1;
|
||||
|
||||
abstract class ChangeNotifier {
|
||||
void addListener();
|
||||
}
|
||||
|
||||
class Notifier1 implements ChangeNotifier {
|
||||
@pragma('vm:never-inline')
|
||||
void addListener() {
|
||||
listener = 1;
|
||||
}
|
||||
}
|
||||
|
||||
class Notifier2 implements ChangeNotifier {
|
||||
@pragma('vm:never-inline')
|
||||
void addListener() {
|
||||
listener = 2;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class M {
|
||||
// This field is unreachable and only serves as
|
||||
// an interface target.
|
||||
@pragma("vm:entry-point")
|
||||
final ChangeNotifier accessibilityFocus = Notifier2();
|
||||
}
|
||||
|
||||
class B implements M {
|
||||
@pragma("vm:entry-point")
|
||||
final ChangeNotifier accessibilityFocus = Notifier1();
|
||||
}
|
||||
|
||||
class C implements M {
|
||||
@pragma("vm:entry-point")
|
||||
final ChangeNotifier accessibilityFocus = Notifier2();
|
||||
}
|
||||
|
||||
// Clobber values on top of the stack.
|
||||
@pragma('vm:never-inline')
|
||||
@pragma("vm:entry-point")
|
||||
void boxed(int a, int b) {
|
||||
print(a);
|
||||
print(b);
|
||||
}
|
||||
|
||||
M instance = opaqueTrue ? B() : C();
|
||||
|
||||
void main(List<String> args) {
|
||||
boxed(1, 2);
|
||||
instance.accessibilityFocus.addListener();
|
||||
Expect.equals(1, listener);
|
||||
}
|
||||
Reference in New Issue
Block a user