mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:21:07 +00:00
[VM/runtime] Fix optimization for reusing instantiator type argument vector.
The bit vector representing the nullability of the types of a type argument vector was stored in reverse order. This caused a problem when a longer instantiated vector is reused for a shorter uninstantiated vector. This fixes https://github.com/dart-lang/sdk/issues/45529 TEST=added regression test Change-Id: I0e936e45d51fa896d7562f4f03c8878437eb464f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193751 Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
4d696edc97
commit
d0ee565bf8
|
@ -5976,23 +5976,24 @@ intptr_t TypeArguments::ComputeNullability() const {
|
|||
if (num_types <= kNullabilityMaxTypes) {
|
||||
AbstractType& type = AbstractType::Handle();
|
||||
for (intptr_t i = 0; i < num_types; i++) {
|
||||
result <<= kNullabilityBitsPerType;
|
||||
type = TypeAt(i);
|
||||
intptr_t type_bits = 0;
|
||||
if (!type.IsNull() && !type.IsNullTypeRef()) {
|
||||
switch (type.nullability()) {
|
||||
case Nullability::kNullable:
|
||||
result |= kNullableBits;
|
||||
type_bits = kNullableBits;
|
||||
break;
|
||||
case Nullability::kNonNullable:
|
||||
result |= kNonNullableBits;
|
||||
type_bits = kNonNullableBits;
|
||||
break;
|
||||
case Nullability::kLegacy:
|
||||
result |= kLegacyBits;
|
||||
type_bits = kLegacyBits;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
result |= (type_bits << (i * kNullabilityBitsPerType));
|
||||
}
|
||||
}
|
||||
set_nullability(result);
|
||||
|
|
|
@ -7368,10 +7368,12 @@ class TypeArguments : public Instance {
|
|||
// 2 bits per type:
|
||||
// - the high bit is set if the type is nullable or legacy.
|
||||
// - the low bit is set if the type is nullable.
|
||||
// The nullabilty is 0 if the vector is longer than kNullabilityMaxTypes.
|
||||
// The nullability is 0 if the vector is longer than kNullabilityMaxTypes.
|
||||
// The condition evaluated at runtime to decide whether UTA can share ITA is
|
||||
// (UTA.nullability & ITA.nullability) == UTA.nullability
|
||||
// Note that this allows for ITA to be longer than UTA.
|
||||
// Note that this allows for ITA to be longer than UTA (the bit vector must be
|
||||
// stored in the same order as the corresponding type vector, i.e. with the
|
||||
// least significant 2 bits representing the nullability of the first type).
|
||||
static const intptr_t kNullabilityBitsPerType = 2;
|
||||
static const intptr_t kNullabilityMaxTypes =
|
||||
kSmiBits / kNullabilityBitsPerType;
|
||||
|
|
24
tests/language/regress/regress45529_test.dart
Normal file
24
tests/language/regress/regress45529_test.dart
Normal file
|
@ -0,0 +1,24 @@
|
|||
// 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 "package:expect/expect.dart";
|
||||
|
||||
void main() {
|
||||
final baz = Foo<Null>().baz;
|
||||
Expect.equals("Baz<Bar<Null>?>", baz.runtimeType.toString());
|
||||
baz.v = baz.v;
|
||||
}
|
||||
|
||||
class Bar<T> {}
|
||||
|
||||
class Foo<T> extends Quux<Bar<T>> {}
|
||||
|
||||
class Baz<T> {
|
||||
Baz(this.v);
|
||||
T v;
|
||||
}
|
||||
|
||||
class Quux<T> {
|
||||
final baz = Baz<T?>(null);
|
||||
}
|
Loading…
Reference in a new issue