From d7d723327f211995e27e10046aeabc4a02a00975 Mon Sep 17 00:00:00 2001 From: Alexander Markov Date: Fri, 22 May 2026 10:10:19 -0700 Subject: [PATCH] [modular_aot] Serialization of type parameter declarations in module snapshots TEST=ci Issue: https://github.com/dart-lang/sdk/issues/61635 Change-Id: Ia5646ec6e2133a2232ffbbdb4926d94296bcd690 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/505522 Commit-Queue: Alexander Markov Reviewed-by: Slava Egorov --- .../lib/snapshot/snapshot.dart | 124 ++++++++++++------ runtime/vm/module_snapshot.cc | 29 +++- runtime/vm/raw_object.h | 2 + 3 files changed, 115 insertions(+), 40 deletions(-) diff --git a/pkg/native_compiler/lib/snapshot/snapshot.dart b/pkg/native_compiler/lib/snapshot/snapshot.dart index 2236570e7ec..16c4db06f5b 100644 --- a/pkg/native_compiler/lib/snapshot/snapshot.dart +++ b/pkg/native_compiler/lib/snapshot/snapshot.dart @@ -360,6 +360,7 @@ class SnapshotSerializer { ast.StructuralParameterType() => getPredefinedCluster( PredefinedClusters.typeParameterTypes, ), + TypeParameters() => getPredefinedCluster(PredefinedClusters.typeParameters), TypeArgumentsConstant() => getPredefinedCluster( PredefinedClusters.typeArguments, ), @@ -379,40 +380,39 @@ class SnapshotSerializer { SerializationCluster getInstanceCluster(ast.Class cls) => (_instanceClusters[cls] ??= InstanceSerializationCluster(cls)); - SerializationCluster _createPredefinedCluster( - PredefinedClusters clusterId, - ) => switch (clusterId) { - .libraryRefs => LibraryRefSerializationCluster(), - .classRefs => ClassRefSerializationCluster(), - .fieldRefs => FieldRefSerializationCluster(), - .functionRefs => FunctionRefSerializationCluster(), - .closureFunctionRefs => ClosureFunctionRefSerializationCluster(), - .closureRefs => ClosureRefSerializationCluster(), - .argumentsDescriptorRefs => ArgumentsDescriptorRefSerializationCluster(), - .recordShapeRefs => RecordShapeRefSerializationCluster(), - .oneByteStrings => OneByteStringSerializationCluster(), - .twoByteStrings => TwoByteStringSerializationCluster(), - .privateNames => PrivateNameSerializationCluster(), - .ints => IntSerializationCluster(), - .doubles => DoubleSerializationCluster(), - .lists => ListSerializationCluster(), - .maps => MapSerializationCluster(), - .sets => SetSerializationCluster(), - .records => RecordSerializationCluster(), - .instantiatedClosures => throw 'Unimplemented cluster $clusterId', - .typeParameters => - throw 'Unimplemented cluster $clusterId', // TypeParametersSerializationCluster(), - .typeArguments => TypeArgumentsSerializationCluster(), - .interfaceTypes => InterfaceTypeSerializationCluster(), - .functionTypes => FunctionTypeSerializationCluster(), - .recordTypes => RecordTypeSerializationCluster(), - .typeParameterTypes => TypeParameterTypeSerializationCluster(), - .codes => CodeSerializationCluster(), - .icDatas => ICDataSerializationCluster(), - .subtypeTestCaches => SubtypeTestCacheSerializationCluster(), - .objectPools => ObjectPoolSerializationCluster(), - .instances => throw 'Each class has a separate instance cluster', - }; + SerializationCluster _createPredefinedCluster(PredefinedClusters clusterId) => + switch (clusterId) { + .libraryRefs => LibraryRefSerializationCluster(), + .classRefs => ClassRefSerializationCluster(), + .fieldRefs => FieldRefSerializationCluster(), + .functionRefs => FunctionRefSerializationCluster(), + .closureFunctionRefs => ClosureFunctionRefSerializationCluster(), + .closureRefs => ClosureRefSerializationCluster(), + .argumentsDescriptorRefs => + ArgumentsDescriptorRefSerializationCluster(), + .recordShapeRefs => RecordShapeRefSerializationCluster(), + .oneByteStrings => OneByteStringSerializationCluster(), + .twoByteStrings => TwoByteStringSerializationCluster(), + .privateNames => PrivateNameSerializationCluster(), + .ints => IntSerializationCluster(), + .doubles => DoubleSerializationCluster(), + .lists => ListSerializationCluster(), + .maps => MapSerializationCluster(), + .sets => SetSerializationCluster(), + .records => RecordSerializationCluster(), + .instantiatedClosures => throw 'Unimplemented cluster $clusterId', + .typeParameters => TypeParametersSerializationCluster(), + .typeArguments => TypeArgumentsSerializationCluster(), + .interfaceTypes => InterfaceTypeSerializationCluster(), + .functionTypes => FunctionTypeSerializationCluster(), + .recordTypes => RecordTypeSerializationCluster(), + .typeParameterTypes => TypeParameterTypeSerializationCluster(), + .codes => CodeSerializationCluster(), + .icDatas => ICDataSerializationCluster(), + .subtypeTestCaches => SubtypeTestCacheSerializationCluster(), + .objectPools => ObjectPoolSerializationCluster(), + .instances => throw 'Each class has a separate instance cluster', + }; } /// AST Constant which wraps an arbitrary object. @@ -1221,8 +1221,58 @@ final class InterfaceTypeSerializationCluster extends SerializationCluster { /// Declaration of type parameters, corresponds to the VM TypeParameters object. class TypeParameters { - final List params; - TypeParameters(this.params); + final ast.ListConstant names; + final TypeArgumentsConstant bounds; + final TypeArgumentsConstant defaultTypes; + + TypeParameters._(this.names, this.bounds, this.defaultTypes); + + factory TypeParameters.fromStructuralParameters( + List params, + ) { + final names = getListConstant([for (final p in params) p.name!]); + final bounds = TypeArgumentsConstant([for (final p in params) p.bound]); + final defaultTypes = TypeArgumentsConstant([ + for (final p in params) p.defaultType, + ]); + return TypeParameters._(names, bounds, defaultTypes); + } +} + +final class TypeParametersSerializationCluster extends SerializationCluster { + final List _objects = []; + + @override + void trace(SnapshotSerializer serializer, Object object) { + final obj = object as TypeParameters; + _objects.add(obj); + serializer.push(obj.names); + serializer.push(obj.bounds); + serializer.push(obj.defaultTypes); + } + + @override + void writePreLoad(SnapshotSerializer serializer) { + serializer.writeUint(PredefinedClusters.typeParameters.index); + } + + @override + void writeAlloc(SnapshotSerializer serializer) { + serializer.writeUint(_objects.length); + for (final obj in _objects) { + serializer.assignRef(obj); + } + } + + @override + void writeFill(SnapshotSerializer serializer) { + for (var i = 0; i < _objects.length; i++) { + final obj = _objects[i]; + serializer.writeRefId(obj.names); + serializer.writeRefId(obj.bounds); + serializer.writeRefId(obj.defaultTypes); + } + } } final class FunctionTypeSerializationCluster extends SerializationCluster { @@ -1250,7 +1300,7 @@ final class FunctionTypeSerializationCluster extends SerializationCluster { } } final typeParameters = type.typeParameters.isNotEmpty - ? TypeParameters(type.typeParameters) + ? TypeParameters.fromStructuralParameters(type.typeParameters) : null; final parameterTypes = getListConstant([ const ast.DynamicType(), // implicit closure parameter diff --git a/runtime/vm/module_snapshot.cc b/runtime/vm/module_snapshot.cc index 07f01b22d89..c3920617657 100644 --- a/runtime/vm/module_snapshot.cc +++ b/runtime/vm/module_snapshot.cc @@ -931,6 +931,31 @@ class InstanceDeserializationCluster : public DeserializationCluster { intptr_t instance_size_ = 0; }; +class TypeParametersDeserializationCluster : public DeserializationCluster { + public: + TypeParametersDeserializationCluster() + : DeserializationCluster("TypeParameters") {} + ~TypeParametersDeserializationCluster() {} + + void ReadAlloc(Deserializer* d) override { + ReadAllocFixedSize(d, TypeParameters::InstanceSize()); + } + + void ReadFill(Deserializer* d_) override { + Deserializer::Local d(d_); + + for (intptr_t id = start_index_, n = stop_index_; id < n; id++) { + TypeParametersPtr tps = static_cast(d.Ref(id)); + Deserializer::InitializeHeader(tps, kTypeParametersCid, + TypeParameters::InstanceSize()); + tps->untag()->names_ = static_cast(d.ReadRef()); + tps->untag()->flags_ = static_cast(d.null()); + tps->untag()->bounds_ = static_cast(d.ReadRef()); + tps->untag()->defaults_ = static_cast(d.ReadRef()); + } + } +}; + class TypeArgumentsDeserializationCluster : public DeserializationCluster { public: TypeArgumentsDeserializationCluster() @@ -1544,9 +1569,7 @@ DeserializationCluster* Deserializer::ReadCluster() { UNIMPLEMENTED(); return nullptr; case ModuleSnapshot::kTypeParameters: - // return new (Z) TypeParametersDeserializationCluster(); - UNIMPLEMENTED(); - return nullptr; + return new (Z) TypeParametersDeserializationCluster(); case ModuleSnapshot::kInterfaceTypes: return new (Z) InterfaceTypeDeserializationCluster(); case ModuleSnapshot::kFunctionTypes: diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 4dd2142ba6c..11d1e8d757e 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -63,6 +63,7 @@ class SetDeserializationCluster; class SubtypeTestCacheDeserializationCluster; class TypeArgumentsDeserializationCluster; class TypeParameterTypeDeserializationCluster; +class TypeParametersDeserializationCluster; } // namespace module_snapshot #define DEFINE_CONTAINS_COMPRESSED(type) \ @@ -2951,6 +2952,7 @@ class UntaggedTypeParameters : public UntaggedObject { CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); } friend class Object; + friend class module_snapshot::TypeParametersDeserializationCluster; }; class UntaggedAbstractType : public UntaggedInstance {