diff --git a/pkg/native_compiler/lib/runtime/type_utils.dart b/pkg/native_compiler/lib/runtime/type_utils.dart index f891c91eb48..70c90d77904 100644 --- a/pkg/native_compiler/lib/runtime/type_utils.dart +++ b/pkg/native_compiler/lib/runtime/type_utils.dart @@ -117,6 +117,14 @@ int computeIndexOfTypeParameter(ast.TypeParameter tp) { return index; } +/// Return enclosing member of the given [node]. +ast.Member getEnclosingMember(ast.TreeNode node) { + do { + node = node.parent!; + } while (node is! ast.Member); + return node; +} + /// Returns true if [field] has a non-trivial initializer. /// /// VM does not allow field initializer functions for fields diff --git a/pkg/native_compiler/lib/snapshot/snapshot.dart b/pkg/native_compiler/lib/snapshot/snapshot.dart index 5a3ad49e1b2..22c59594378 100644 --- a/pkg/native_compiler/lib/snapshot/snapshot.dart +++ b/pkg/native_compiler/lib/snapshot/snapshot.dart @@ -389,7 +389,7 @@ class SnapshotSerializer { .interfaceTypes => InterfaceTypeSerializationCluster(), .functionTypes => FunctionTypeSerializationCluster(), .recordTypes => throw 'Unimplemented cluster $clusterId', - .typeParameterTypes => throw 'Unimplemented cluster $clusterId', + .typeParameterTypes => TypeParameterTypeSerializationCluster(), .codes => CodeSerializationCluster(), .icDatas => ICDataSerializationCluster(), .subtypeTestCaches => SubtypeTestCacheSerializationCluster(), @@ -1145,6 +1145,15 @@ final class FunctionTypeSerializationCluster extends SerializationCluster { void trace(SnapshotSerializer serializer, Object object) { final type = object as ast.FunctionType; _objects.add(type); + if (type.typeParameters.isNotEmpty) { + // Establish StructuralParameter -> owner links. + final typeParamCluster = + serializer.getPredefinedCluster(PredefinedClusters.typeParameterTypes) + as TypeParameterTypeSerializationCluster; + for (final tp in type.typeParameters) { + typeParamCluster._structuralParameterOwner[tp] = type; + } + } final typeParameters = type.typeParameters.isNotEmpty ? TypeParameters(type.typeParameters) : null; @@ -1200,6 +1209,100 @@ final class FunctionTypeSerializationCluster extends SerializationCluster { } } +final class TypeParameterTypeSerializationCluster extends SerializationCluster { + final List _objects = []; + + // Filled by FunctionTypeSerializationCluster when tracing corresponding + // function types, as there is no link in the AST. + final Map + _structuralParameterOwner = {}; + + Object _getTypeParameterOwner( + SnapshotSerializer serializer, + ast.GenericDeclaration declaration, + ) { + switch (declaration) { + case ast.Class(): + return declaration; + case ast.Procedure(): + return serializer.functionRegistry.getFunction( + declaration, + isGetter: declaration.isGetter, + isSetter: declaration.isSetter, + ); + case ast.LocalFunction(): + return serializer.functionRegistry.getFunction( + getEnclosingMember(declaration), + localFunction: declaration, + ); + default: + throw 'Unexpected type parameter declaration ${declaration.runtimeType} $declaration'; + } + } + + @override + void trace(SnapshotSerializer serializer, Object object) { + final type = object as ast.DartType; + _objects.add(type); + switch (type) { + case ast.TypeParameterType(): + serializer.push( + _getTypeParameterOwner(serializer, type.parameter.declaration!), + ); + break; + case ast.StructuralParameterType(): + serializer.push(_structuralParameterOwner[type.parameter]!); + break; + default: + throw 'Unexpected type parameter ${type.runtimeType} $type'; + } + } + + @override + void writePreLoad(SnapshotSerializer serializer) { + serializer.writeUint(PredefinedClusters.typeParameterTypes.index); + } + + @override + void writeAlloc(SnapshotSerializer serializer) { + serializer.writeUint(_objects.length); + for (final type in _objects) { + serializer.assignRef(type); + } + } + + @override + void writeFill(SnapshotSerializer serializer) { + for (var i = 0; i < _objects.length; i++) { + final type = _objects[i]; + serializer.writeUint( + type.declaredNullability == ast.Nullability.nullable ? 1 : 0, + ); + Object owner; + int index; + switch (type) { + case ast.TypeParameterType(): + owner = _getTypeParameterOwner( + serializer, + type.parameter.declaration!, + ); + index = computeIndexOfTypeParameter(type.parameter); + break; + case ast.StructuralParameterType(): + final functionType = _structuralParameterOwner[type.parameter]!; + owner = functionType; + index = functionType.typeParameters.indexOf(type.parameter); + break; + default: + throw 'Unexpected type parameter ${type.runtimeType} $type'; + } + assert(index >= 0); + serializer.writeRefId(owner); + serializer.writeUint(index); + } + } +} + final class CodeSerializationCluster extends SerializationCluster { final List _objects = []; diff --git a/runtime/vm/module_snapshot.cc b/runtime/vm/module_snapshot.cc index 90c7d8b46a9..06d619780dc 100644 --- a/runtime/vm/module_snapshot.cc +++ b/runtime/vm/module_snapshot.cc @@ -1009,6 +1009,63 @@ class InterfaceTypeDeserializationCluster : public DeserializationCluster { } }; +class TypeParameterTypeDeserializationCluster : public DeserializationCluster { + public: + TypeParameterTypeDeserializationCluster() + : DeserializationCluster( + "TypeParameterType", + Object::ShouldHaveDeeplyImmutabilityBitSet(kTypeParameterCid)) {} + ~TypeParameterTypeDeserializationCluster() {} + + void ReadAlloc(Deserializer* d) override { + ReadAllocFixedSize(d, TypeParameter::InstanceSize()); + } + + void ReadFill(Deserializer* d_) override { + Deserializer::Local d(d_); + + for (intptr_t id = start_index_, n = stop_index_; id < n; id++) { + TypeParameterPtr tp = static_cast(d.Ref(id)); + Deserializer::InitializeHeader(tp, kTypeParameterCid, + TypeParameter::InstanceSize(), + is_deeply_immutable()); + tp->untag()->type_test_stub_entry_point_.store(0, + std::memory_order_relaxed); + const intptr_t is_nullable = d.ReadUnsigned(); + ObjectPtr owner = d.ReadRef(); + intptr_t flags = UntaggedAbstractType::NullabilityBit::update( + is_nullable, UntaggedAbstractType::TypeStateBits::encode( + UntaggedAbstractType::kAllocated)); + if (owner->IsClass()) { + owner = Smi::New(static_cast(owner)->untag()->id()); + } else { + if (owner->IsFunction()) { + owner = Function::RawCast(owner)->untag()->signature(); + } + flags = + UntaggedTypeParameter::IsFunctionTypeParameter::update(true, flags); + } + tp->untag()->set_flags(flags); + tp->untag()->type_test_stub_ = static_cast(d.null()); + tp->untag()->hash_ = Smi::New(0); + tp->untag()->owner_ = owner; + tp->untag()->base_ = 0; + tp->untag()->index_ = d.ReadUnsigned(); + } + } + + void PostLoad(Deserializer* d, const Array& refs) override { + TypeParameter& type = TypeParameter::Handle(d->zone()); + Code& stub = Code::Handle(d->zone()); + for (intptr_t id = start_index_, n = stop_index_; id < n; id++) { + type ^= refs.At(id); + stub = TypeTestingStubGenerator::DefaultCodeForType(type); + type.InitializeTypeTestingStubNonAtomic(stub); + type.SetIsFinalized(); + } + } +}; + class CodeDeserializationCluster : public DeserializationCluster { public: explicit CodeDeserializationCluster(Zone* zone) @@ -1366,9 +1423,7 @@ DeserializationCluster* Deserializer::ReadCluster() { UNIMPLEMENTED(); return nullptr; case ModuleSnapshot::kTypeParameterTypes: - // return new (Z) TypeParameterTypeDeserializationCluster(); - UNIMPLEMENTED(); - return nullptr; + return new (Z) TypeParameterTypeDeserializationCluster(); case ModuleSnapshot::kTypeArguments: return new (Z) TypeArgumentsDeserializationCluster(); case ModuleSnapshot::kCodes: diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index acc0a66d46a..23ac3dc7327 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -60,6 +60,7 @@ class ObjectPoolDeserializationCluster; class SetDeserializationCluster; class SubtypeTestCacheDeserializationCluster; class TypeArgumentsDeserializationCluster; +class TypeParameterTypeDeserializationCluster; } // namespace module_snapshot #define DEFINE_CONTAINS_COMPRESSED(type) \ @@ -3095,6 +3096,7 @@ class UntaggedTypeParameter : public UntaggedAbstractType { CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); } friend class CidRewriteVisitor; + friend class module_snapshot::TypeParameterTypeDeserializationCluster; }; class UntaggedClosure : public UntaggedInstance {