Skip to content

Commit ea57b1e

Browse files
creliercommit-bot@chromium.org
authored andcommitted
[VM/nnbd] Pass nullability when creating Class::DeclarationType.
Passing nullability rather than forcing kLegacy helps slightly reduce the number of Types in the VM and in snapshots. This allows to remove the kludge about declaration type of Null being kNullable. Also pass nullability when creating a simple type may help. Note that CFE is still producing super types and some interface types that are non-nullable, even with nnbd features disabled. But this should get fixed and further reduce the number of types in the snapshot. Change-Id: I397f00902026ee5bc91d36328f4156427702efdb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/124480 Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
1 parent fa43799 commit ea57b1e

File tree

6 files changed

+85
-85
lines changed

6 files changed

+85
-85
lines changed

runtime/vm/compiler/backend/il_deserializer.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1848,7 +1848,7 @@ bool FlowGraphDeserializer::ParseType(SExpression* sexp, Object* out) {
18481848
}
18491849
// Guaranteed not to re-enter ParseType.
18501850
if (!ParseClass(cls_sexp, &type_class_)) return false;
1851-
*out = Type::New(type_class_, *type_args_ptr, token_pos, Heap::kOld);
1851+
*out = Type::New(type_class_, *type_args_ptr, token_pos);
18521852
auto& type = Type::Cast(*out);
18531853
if (auto const sig_sexp = list->ExtraLookupValue("signature")) {
18541854
auto& function = Function::Handle(zone());

runtime/vm/compiler/frontend/bytecode_reader.cc

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,14 +1669,7 @@ RawObject* BytecodeReaderHelper::ReadType(intptr_t tag,
16691669
if (!cls.is_declaration_loaded()) {
16701670
LoadReferencedClass(cls);
16711671
}
1672-
Type& type = Type::Handle(Z, cls.DeclarationType());
1673-
// TODO(regis): Remove this workaround once nullability of Null provided
1674-
// by CFE is always kNullable.
1675-
if (type.IsNullType()) {
1676-
ASSERT(type.IsNullable());
1677-
return type.raw();
1678-
}
1679-
return type.ToNullability(nullability, Heap::kOld);
1672+
return cls.DeclarationType(nullability);
16801673
}
16811674
case kTypeParameter: {
16821675
Object& parent = Object::Handle(Z, ReadObject());
@@ -1710,9 +1703,9 @@ RawObject* BytecodeReaderHelper::ReadType(intptr_t tag,
17101703
}
17111704
const TypeArguments& type_arguments =
17121705
TypeArguments::CheckedHandle(Z, ReadObject());
1713-
const Type& type = Type::Handle(
1714-
Z, Type::New(cls, type_arguments, TokenPosition::kNoSource));
1715-
type.set_nullability(nullability);
1706+
const Type& type =
1707+
Type::Handle(Z, Type::New(cls, type_arguments,
1708+
TokenPosition::kNoSource, nullability));
17161709
type.SetIsFinalized();
17171710
return type.Canonicalize();
17181711
}
@@ -1742,9 +1735,9 @@ RawObject* BytecodeReaderHelper::ReadType(intptr_t tag,
17421735
pending_recursive_types_->SetLength(id);
17431736
pending_recursive_types_ = saved_pending_recursive_types;
17441737

1745-
Type& type = Type::Handle(
1746-
Z, Type::New(cls, type_arguments, TokenPosition::kNoSource));
1747-
type.set_nullability(nullability);
1738+
Type& type =
1739+
Type::Handle(Z, Type::New(cls, type_arguments,
1740+
TokenPosition::kNoSource, nullability));
17481741
type_ref.set_type(type);
17491742
type.SetIsFinalized();
17501743
if (id != 0) {

runtime/vm/compiler/frontend/kernel_to_il.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2226,8 +2226,7 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodForwarder(
22262226
Function::ZoneHandle(Z, function.parent_function());
22272227
const Class& owner = Class::ZoneHandle(Z, parent.Owner());
22282228
AbstractType& type = AbstractType::ZoneHandle(Z);
2229-
type = Type::New(owner, TypeArguments::Handle(Z), owner.token_pos(),
2230-
Heap::kOld);
2229+
type = Type::New(owner, TypeArguments::Handle(Z), owner.token_pos());
22312230
type = ClassFinalizer::FinalizeType(owner, type);
22322231
body += Constant(type);
22332232
} else {

runtime/vm/compiler/frontend/kernel_translation_helper.cc

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2768,9 +2768,8 @@ void TypeTranslator::BuildTypeInternal() {
27682768
result_ = Object::void_type().raw();
27692769
break;
27702770
case kBottomType:
2771-
result_ =
2772-
Class::Handle(Z, I->object_store()->null_class()).DeclarationType();
2773-
// We set the nullability of Null to kNullable, even in legacy mode.
2771+
result_ = Class::Handle(Z, I->object_store()->null_class())
2772+
.DeclarationType(kNullable);
27742773
ASSERT(result_.IsNullable());
27752774
break;
27762775
case kNeverType:
@@ -2815,18 +2814,13 @@ void TypeTranslator::BuildInterfaceType(bool simple) {
28152814
if (simple) {
28162815
if (finalize_ || klass.is_type_finalized()) {
28172816
// Fast path for non-generic types: retrieve or populate the class's only
2818-
// canonical type, which is its declaration type.
2819-
result_ = klass.DeclarationType();
2820-
// TODO(regis): Remove this workaround once nullability of Null provided
2821-
// by CFE is always kNullable.
2822-
if (!result_.IsNullType()) {
2823-
result_ = Type::Cast(result_).ToNullability(nullability, Heap::kOld);
2824-
}
2817+
// canonical type (as long as only one nullability variant is used), which
2818+
// is its declaration type.
2819+
result_ = klass.DeclarationType(nullability);
28252820
} else {
28262821
// Note that the type argument vector is not yet extended.
2827-
result_ =
2828-
Type::New(klass, Object::null_type_arguments(), klass.token_pos());
2829-
Type::Cast(result_).set_nullability(nullability);
2822+
result_ = Type::New(klass, Object::null_type_arguments(),
2823+
klass.token_pos(), nullability);
28302824
}
28312825
return;
28322826
}
@@ -2931,8 +2925,7 @@ void TypeTranslator::BuildFunctionType(bool simple) {
29312925
finalize_ = finalize;
29322926

29332927
Type& signature_type =
2934-
Type::ZoneHandle(Z, signature_function.SignatureType());
2935-
signature_type.set_nullability(nullability);
2928+
Type::ZoneHandle(Z, signature_function.SignatureType(nullability));
29362929

29372930
if (finalize_) {
29382931
signature_type ^=

runtime/vm/object.cc

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -944,13 +944,13 @@ void Object::Init(Isolate* isolate) {
944944
cls.set_is_type_finalized();
945945

946946
cls = dynamic_class_;
947-
*dynamic_type_ = Type::NewNonParameterizedType(cls);
947+
*dynamic_type_ = Type::NewNonParameterizedType(cls, kNullable);
948948

949949
cls = void_class_;
950-
*void_type_ = Type::NewNonParameterizedType(cls);
950+
*void_type_ = Type::NewNonParameterizedType(cls, kNullable);
951951

952952
cls = never_class_;
953-
*never_type_ = Type::NewNonParameterizedType(cls);
953+
*never_type_ = Type::NewNonParameterizedType(cls, kNonNullable);
954954

955955
// Since TypeArguments objects are passed as function arguments, make them
956956
// behave as Dart instances, although they are just VM objects.
@@ -1567,7 +1567,7 @@ RawError* Object::Init(Isolate* isolate,
15671567
cls = object_store->array_class(); // Was allocated above.
15681568
RegisterPrivateClass(cls, Symbols::_List(), core_lib);
15691569
pending_classes.Add(cls);
1570-
// We cannot use NewNonParameterizedType(cls), because Array is
1570+
// We cannot use NewNonParameterizedType(), because Array is
15711571
// parameterized. Warning: class _List has not been patched yet. Its
15721572
// declared number of type parameters is still 0. It will become 1 after
15731573
// patching. The array type allocated below represents the raw type _List
@@ -1934,7 +1934,8 @@ RawError* Object::Init(Isolate* isolate,
19341934
// name is a built-in identifier (this is wrong). The corresponding types
19351935
// are stored in the object store.
19361936
cls = object_store->null_class();
1937-
type = Type::NewNonParameterizedType(cls);
1937+
type = Type::NewNonParameterizedType(cls, kNullable);
1938+
cls.set_declaration_type(type);
19381939
object_store->set_null_type(type);
19391940
ASSERT(type.IsNullable());
19401941

@@ -4335,18 +4336,23 @@ void Class::set_declaration_type(const Type& value) const {
43354336
// TODO(regis): Since declaration type is used as the runtime type of
43364337
// instances of a non-generic class, the nullability should be set to
43374338
// kNonNullable instead of kLegacy.
4338-
// For now, we set the nullability to kLegacy, except for Null.
4339-
ASSERT(value.IsLegacy() || (value.IsNullType() && value.IsNullable()));
4339+
// For now, we accept any except for Null (kNullable).
4340+
ASSERT(!value.IsNullType() || value.IsNullable());
43404341
StorePointer(&raw_ptr()->declaration_type_, value.raw());
43414342
}
43424343

4343-
RawType* Class::DeclarationType() const {
4344+
RawType* Class::DeclarationType(Nullability nullability) const {
43444345
ASSERT(is_declaration_loaded());
4345-
if (declaration_type() != Type::null()) {
4346-
return declaration_type();
4346+
if (IsNullClass()) {
4347+
// Ignore requested nullability (e.g. by mirrors).
4348+
nullability = kNullable;
4349+
}
4350+
Type& type = Type::Handle(declaration_type());
4351+
if (!type.IsNull()) {
4352+
return type.ToNullability(nullability, Heap::kOld);
43474353
}
4348-
Type& type = Type::Handle(
4349-
Type::New(*this, TypeArguments::Handle(type_parameters()), token_pos()));
4354+
type = Type::New(*this, TypeArguments::Handle(type_parameters()), token_pos(),
4355+
nullability);
43504356
type ^= ClassFinalizer::FinalizeType(*this, type);
43514357
set_declaration_type(type);
43524358
return type.raw();
@@ -6318,8 +6324,8 @@ RawType* Function::SignatureType(Nullability nullability) const {
63186324
const TypeArguments& signature_type_arguments =
63196325
TypeArguments::Handle(scope_class.type_parameters());
63206326
// Return the still unfinalized signature type.
6321-
type = Type::New(scope_class, signature_type_arguments, token_pos());
6322-
type.set_nullability(nullability);
6327+
type = Type::New(scope_class, signature_type_arguments, token_pos(),
6328+
nullability);
63236329
type.set_signature(*this);
63246330
SetSignatureType(type);
63256331
}
@@ -16656,7 +16662,10 @@ RawAbstractType* Instance::GetType(Heap::Space space) const {
1665616662
if (cls.NumTypeArguments() > 0) {
1665716663
type_arguments = GetTypeArguments();
1665816664
}
16659-
type = Type::New(cls, type_arguments, TokenPosition::kNoSource, space);
16665+
// TODO(regis): The runtime type of a non-null instance should be
16666+
// non-nullable instead of legacy. Revisit.
16667+
type = Type::New(cls, type_arguments, TokenPosition::kNoSource, kLegacy,
16668+
space);
1666016669
type.SetIsFinalized();
1666116670
type ^= type.Canonicalize();
1666216671
}
@@ -17640,20 +17649,22 @@ RawType* Type::DartTypeType() {
1764017649
return Isolate::Current()->object_store()->type_type();
1764117650
}
1764217651

17643-
RawType* Type::NewNonParameterizedType(const Class& type_class) {
17652+
RawType* Type::NewNonParameterizedType(const Class& type_class,
17653+
Nullability nullability) {
1764417654
ASSERT(type_class.NumTypeArguments() == 0);
1764517655
// It is too early to use the class finalizer, as type_class may not be named
1764617656
// yet, so do not call DeclarationType().
1764717657
Type& type = Type::Handle(type_class.declaration_type());
1764817658
if (type.IsNull()) {
1764917659
type = Type::New(Class::Handle(type_class.raw()),
17650-
Object::null_type_arguments(), TokenPosition::kNoSource);
17660+
Object::null_type_arguments(), TokenPosition::kNoSource,
17661+
nullability);
1765117662
type.SetIsFinalized();
1765217663
type ^= type.Canonicalize();
1765317664
type_class.set_declaration_type(type);
1765417665
}
1765517666
ASSERT(type.IsFinalized());
17656-
return type.raw();
17667+
return type.ToNullability(nullability, Heap::kOld);
1765717668
}
1765817669

1765917670
void Type::SetIsFinalized() const {
@@ -17789,8 +17800,8 @@ RawAbstractType* Type::InstantiateFrom(
1778917800
}
1779017801
// This uninstantiated type is not modified, as it can be instantiated
1779117802
// with different instantiators. Allocate a new instantiated version of it.
17792-
const Type& instantiated_type =
17793-
Type::Handle(zone, Type::New(cls, type_arguments, token_pos(), space));
17803+
const Type& instantiated_type = Type::Handle(
17804+
zone, Type::New(cls, type_arguments, token_pos(), nullability(), space));
1779417805
// For a function type, possibly instantiate and set its signature.
1779517806
if (!sig_fun.IsNull()) {
1779617807
// If we are finalizing a typedef, do not yet instantiate its signature,
@@ -18009,10 +18020,8 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const {
1800918020
const Class& cls = Class::Handle(zone, type_class());
1801018021

1801118022
// Fast canonical lookup/registry for simple types.
18012-
if (IsNullType() || (IsLegacy() && !cls.IsGeneric() &&
18013-
!cls.IsClosureClass() && !cls.IsTypedefClass())) {
18023+
if (!cls.IsGeneric() && !cls.IsClosureClass() && !cls.IsTypedefClass()) {
1801418024
ASSERT(!IsFunctionType());
18015-
ASSERT(!IsNullType() || IsNullable());
1801618025
Type& type = Type::Handle(zone, cls.declaration_type());
1801718026
if (type.IsNull()) {
1801818027
ASSERT(!cls.raw()->InVMIsolateHeap() || (isolate == Dart::vm_isolate()));
@@ -18045,10 +18054,12 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const {
1804518054
}
1804618055
}
1804718056
}
18048-
ASSERT(this->Equals(type));
18049-
ASSERT(type.IsCanonical());
18050-
ASSERT(type.IsOld());
18051-
return type.raw();
18057+
if (nullability() == type.nullability()) {
18058+
ASSERT(this->Equals(type));
18059+
ASSERT(type.IsCanonical());
18060+
ASSERT(type.IsOld());
18061+
return type.raw();
18062+
}
1805218063
}
1805318064

1805418065
AbstractType& type = Type::Handle(zone);
@@ -18136,12 +18147,13 @@ bool Type::CheckIsCanonical(Thread* thread) const {
1813618147
const Class& cls = Class::Handle(zone, type_class());
1813718148

1813818149
// Fast canonical lookup/registry for simple types.
18139-
if (IsNullType() || (IsLegacy() && !cls.IsGeneric() &&
18140-
!cls.IsClosureClass() && !cls.IsTypedefClass())) {
18150+
if (!cls.IsGeneric() && !cls.IsClosureClass() && !cls.IsTypedefClass()) {
1814118151
ASSERT(!IsFunctionType());
18142-
ASSERT(!IsNullType() || IsNullable());
1814318152
type = cls.declaration_type();
18144-
return (raw() == type.raw());
18153+
ASSERT(type.IsCanonical());
18154+
if (nullability() == type.nullability()) {
18155+
return (raw() == type.raw());
18156+
}
1814518157
}
1814618158

1814718159
ObjectStore* object_store = isolate->object_store();
@@ -18234,6 +18246,7 @@ RawType* Type::New(Heap::Space space) {
1823418246
RawType* Type::New(const Class& clazz,
1823518247
const TypeArguments& arguments,
1823618248
TokenPosition token_pos,
18249+
Nullability nullability,
1823718250
Heap::Space space) {
1823818251
Zone* Z = Thread::Current()->zone();
1823918252
const Type& result = Type::Handle(Z, Type::New(space));
@@ -18242,11 +18255,7 @@ RawType* Type::New(const Class& clazz,
1824218255
result.SetHash(0);
1824318256
result.set_token_pos(token_pos);
1824418257
result.StoreNonPointer(&result.raw_ptr()->type_state_, RawType::kAllocated);
18245-
if (clazz.id() == kNullCid) {
18246-
result.set_nullability(kNullable);
18247-
} else {
18248-
result.set_nullability(kLegacy);
18249-
}
18258+
result.set_nullability(nullability);
1825018259

1825118260
result.SetTypeTestingStub(
1825218261
Code::Handle(Z, TypeTestingStubGenerator::DefaultCodeForType(result)));

runtime/vm/object.h

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,21 @@ typedef ZoneGrowableHandlePtrArray<const AbstractType>* TrailPtr;
837837
// The third string in the triplet is "print" if the triplet should be printed.
838838
typedef ZoneGrowableHandlePtrArray<const String> URIs;
839839

840+
// Keep in sync with package:kernel/lib/ast.dart
841+
enum Nullability {
842+
kUndetermined = 0,
843+
kNullable = 1,
844+
kNonNullable = 2,
845+
kLegacy = 3,
846+
};
847+
848+
// Nullability aware subtype checking modes.
849+
enum NNBDMode {
850+
kUnaware,
851+
kWeak,
852+
kStrong,
853+
};
854+
840855
class Class : public Object {
841856
public:
842857
enum InvocationDispatcherEntry {
@@ -935,7 +950,11 @@ class Class : public Object {
935950
// class B<T, S>
936951
// class C<R> extends B<R, int>
937952
// C.DeclarationType() --> C [R, int, R]
938-
RawType* DeclarationType() const;
953+
// The declaration type is legacy by default, but another nullability
954+
// variant may be requested. The first requested type gets cached in the class
955+
// and subsequent nullability variants get cached in the object store.
956+
// TODO(regis): Is this caching still useful or should we eliminate it?
957+
RawType* DeclarationType(Nullability nullability = kLegacy) const;
939958

940959
static intptr_t declaration_type_offset() {
941960
return OFFSET_OF(RawClass, declaration_type_);
@@ -2130,21 +2149,6 @@ class ICData : public Object {
21302149
friend class SnapshotWriter;
21312150
};
21322151

2133-
// Keep in sync with package:kernel/lib/ast.dart
2134-
enum Nullability {
2135-
kUndetermined = 0,
2136-
kNullable = 1,
2137-
kNonNullable = 2,
2138-
kLegacy = 3,
2139-
};
2140-
2141-
// Nullability aware subtype checking modes.
2142-
enum NNBDMode {
2143-
kUnaware,
2144-
kWeak,
2145-
kStrong,
2146-
};
2147-
21482152
// Often used constants for number of free function type parameters.
21492153
enum {
21502154
kNoneFree = 0,
@@ -7153,11 +7157,13 @@ class Type : public AbstractType {
71537157
static RawType* DartTypeType();
71547158

71557159
// The finalized type of the given non-parameterized class.
7156-
static RawType* NewNonParameterizedType(const Class& type_class);
7160+
static RawType* NewNonParameterizedType(const Class& type_class,
7161+
Nullability nullability = kLegacy);
71577162

71587163
static RawType* New(const Class& clazz,
71597164
const TypeArguments& arguments,
71607165
TokenPosition token_pos,
7166+
Nullability nullability = kLegacy,
71617167
Heap::Space space = Heap::kOld);
71627168

71637169
private:

0 commit comments

Comments
 (0)