@@ -229,40 +229,55 @@ class ClosureLayouter extends RecursiveVisitor {
229229 // 4-...: Entries for calling the closure
230230 static const int vtableBaseIndexGeneric = 4 ;
231231
232- // Base struct for vtables without the dynamic call entry added. Referenced
233- // by [closureBaseStruct] instead of the fully initialized version
234- // ([vtableBaseStruct]) to break the type cycle.
235- late final w.StructType _vtableBaseStructBase = _defineStruct ("#VtableBase" );
232+ // Uninitialized (no field types added yet) struct for base vtable to allow
233+ // cyclic types:
234+ //
235+ // closureBaseStruct.vtable = ref vtableBase
236+ // vtableBaseStruct.dynamicCall = Function(ref closureBaseStruct, ...)
237+ //
238+ late final w.StructType _vtableBaseStructUninitialized =
239+ _defineStruct ("#VtableBase" );
240+
241+ /// Base struct for all closure vtables.
242+ late final w.StructType vtableBaseStruct = (() {
243+ final vtable = _vtableBaseStructUninitialized;
244+ final index = vtable.fields.length;
245+ vtable.fields.add (w.FieldType (
246+ w.RefType .def (translator.dynamicCallVtableEntryFunctionType,
247+ nullable: false ),
248+ mutable: false ));
249+ vtable.fieldNames[index] = 'dynamiClosureCallEntry' ;
250+ return vtable;
251+ })();
236252
237253 /// Base struct for instantiation closure contexts. Type tests against this
238254 /// type is used in `_Closure._equals` to check if a closure is an
239255 /// instantiation.
240256 late final w.StructType instantiationContextBaseStruct =
241- _defineStruct ("#InstantiationClosureContextBase" , fields: [
242- w.FieldType (w.RefType .def (closureBaseStruct, nullable: false ),
257+ _defineStruct ("#InstantiationClosureContextBase" , namedFields: {
258+ 'genericClosure' : w.FieldType (
259+ w.RefType .def (closureBaseStruct, nullable: false ),
243260 mutable: false ),
244- ] );
261+ } );
245262
246263 /// Base struct for non-generic closure vtables.
247- late final w.StructType vtableBaseStruct = _vtableBaseStructBase
248- ..fields.add (w.FieldType (
249- w.RefType .def (translator.dynamicCallVtableEntryFunctionType,
250- nullable: false ),
251- mutable: false ));
264+ late final w.StructType nonGenericVtableBaseStruct =
265+ _defineStruct ("#NonGenericVtableBase" , superType: vtableBaseStruct);
252266
253267 /// Base struct for generic closure vtables.
254- late final w.StructType genericVtableBaseStruct = _defineStruct (
255- "#GenericVtableBase" ,
256- fields: vtableBaseStruct.fields.toList ()
257- ..add (w.FieldType (
258- w.RefType .def (instantiationClosureTypeComparisonFunctionType,
259- nullable: false ),
260- mutable: false ))
261- ..add (w.FieldType (
262- w.RefType .def (instantiationClosureTypeHashFunctionType,
263- nullable: false ),
264- mutable: false )),
265- superType: vtableBaseStruct);
268+ late final w.StructType genericVtableBaseStruct =
269+ _defineStruct ("#GenericVtableBase" ,
270+ namedFields: {
271+ 'closureEqualFun' : w.FieldType (
272+ w.RefType .def (instantiationClosureTypeComparisonFunctionType,
273+ nullable: false ),
274+ mutable: false ),
275+ 'closureHashCodeFun' : w.FieldType (
276+ w.RefType .def (instantiationClosureTypeHashFunctionType,
277+ nullable: false ),
278+ mutable: false ),
279+ },
280+ superType: vtableBaseStruct);
266281
267282 /// Type of [ClosureRepresentation._instantiationTypeComparisonFunction] .
268283 late final w.FunctionType instantiationClosureTypeComparisonFunctionType =
@@ -280,9 +295,29 @@ class ClosureLayouter extends RecursiveVisitor {
280295 [w.NumType .i64], // hash
281296 );
282297
283- // Base struct for closures.
284- late final w.StructType closureBaseStruct = _makeClosureStruct (
285- "#ClosureBase" , _vtableBaseStructBase, translator.closureInfo.struct);
298+ /// Base struct for closures.
299+ ///
300+ /// A closure contains the following fields:
301+ ///
302+ /// Object
303+ /// field0: A class ID (always the `_Closure` class ID)
304+ /// field1: An identity hash
305+ ///
306+ /// _Closure <: Object
307+ /// field2: A context reference (used for `this` in tear-offs)
308+ ///
309+ /// #ClosureBase <: _Closure (defined here)
310+ /// field3: vtable reference
311+ /// field4: function type
312+ ///
313+ late final w.StructType closureBaseStruct = _defineStruct ("#ClosureBase" ,
314+ namedFields: {
315+ 'vtable' : w.FieldType (
316+ w.RefType .def (_vtableBaseStructUninitialized, nullable: false ),
317+ mutable: false ),
318+ 'functionType' : w.FieldType (functionTypeType, mutable: false ),
319+ },
320+ superType: translator.closureInfo.struct);
286321
287322 w.RefType get typeType => translator.types.nonNullableTypeType;
288323
@@ -291,16 +326,16 @@ class ClosureLayouter extends RecursiveVisitor {
291326
292327 final Map <int , w.StructType > _instantiationContextBaseStructs = {};
293328
294- w.StructType _getInstantiationContextBaseStruct (int numTypes) =>
295- _instantiationContextBaseStructs. putIfAbsent (
296- numTypes,
297- () => _defineStruct ( "#InstantiationClosureContextBase-$ numTypes " ,
298- fields : [
299- w. FieldType (w. RefType . def (closureBaseStruct, nullable : false ),
300- mutable : false ) ,
301- ... List . filled (numTypes, w. FieldType (typeType, mutable : false ))
302- ],
303- superType : instantiationContextBaseStruct));
329+ w.StructType _getInstantiationContextBaseStruct (int numTypes) {
330+ final typeField = w. FieldType (typeType, mutable : false );
331+ return _instantiationContextBaseStructs. putIfAbsent (
332+ numTypes,
333+ () => _defineStruct ( "#InstantiationClosureContextBase-$ numTypes " ,
334+ namedFields : {
335+ for ( int i = 0 ; i < numTypes; ++ i) 'typeArgument$ i ' : typeField ,
336+ },
337+ superType : instantiationContextBaseStruct));
338+ }
304339
305340 final Map <int , Map <w.ModuleBuilder , w.BaseFunction >>
306341 _instantiationTypeComparisonFunctions = {};
@@ -324,38 +359,40 @@ class ClosureLayouter extends RecursiveVisitor {
324359 .putIfAbsent (module,
325360 () => _createInstantiationTypeHashFunction (module, numTypes));
326361
362+ /// Add a new struct type to the module.
363+ ///
364+ /// If [superType] is provided, the new struct type will be pre-populated with
365+ /// the fields and field names from the [superType] .
366+ ///
367+ /// If [namedFields] is provided, adds the fields in iteration order to the
368+ /// struct type.
369+ /// NOTE: Call sites can rely on Dart's [Map] guarantees of preserving
370+ /// iteration order (so e.g. `{'a': typeA, 'b': typeB}` is guaranteed to add
371+ /// fields in that order).
372+ ///
373+ /// Additional fields can be added later, by adding to the [fields] list.
374+ /// This enables struct types to be recursive.
327375 w.StructType _defineStruct (String name,
328- {Iterable < w.FieldType >? fields , w.StructType ? superType}) {
329- final type = translator.typesBuilder
330- . defineStruct (name, fields : fields , superType: superType);
376+ {Map < String , w.FieldType >? namedFields , w.StructType ? superType}) {
377+ final type =
378+ translator.typesBuilder. defineStruct (name, superType: superType);
331379 if (translator.dynamicModuleSupportEnabled) {
332380 // Pessimistically assume there will be subtypes in a submodule. This
333381 // ensures the struct is not final in all modules so the types are equal.
334382 type.hasAnySubtypes = true ;
335383 }
384+ if (superType != null ) {
385+ type.fields.addAll (superType.fields);
386+ type.fieldNames.addAll (superType.fieldNames);
387+ }
388+ namedFields? .forEach ((String name, w.FieldType value) {
389+ final int index = type.fields.length;
390+ type.fields.add (value);
391+ type.fieldNames[index] = name;
392+ });
336393 return type;
337394 }
338395
339- w.StructType _makeClosureStruct (
340- String name, w.StructType vtableStruct, w.StructType superType) {
341- // A closure contains:
342- // - A class ID (always the `_Closure` class ID)
343- // - An identity hash
344- // - A context reference (used for `this` in tear-offs)
345- // - A vtable reference
346- // - A `_FunctionType`
347- return _defineStruct (name,
348- fields: [
349- w.FieldType (w.NumType .i32, mutable: false ),
350- w.FieldType (w.NumType .i32),
351- w.FieldType (closureContextFieldType, mutable: false ),
352- w.FieldType (w.RefType .def (vtableStruct, nullable: false ),
353- mutable: false ),
354- w.FieldType (functionTypeType, mutable: false )
355- ],
356- superType: superType);
357- }
358-
359396 w.ValueType get topType => translator.topType;
360397
361398 ClosureLayouter (this .translator)
@@ -450,11 +487,21 @@ class ClosureLayouter extends RecursiveVisitor {
450487 String vtableName = ["#Vtable" , ...nameTags].join ("-" );
451488 String closureName = ["#Closure" , ...nameTags].join ("-" );
452489 w.StructType parentVtableStruct = parent? .vtableStruct ??
453- (typeCount == 0 ? vtableBaseStruct : genericVtableBaseStruct);
454- w.StructType vtableStruct = _defineStruct (vtableName,
455- fields: parentVtableStruct.fields, superType: parentVtableStruct);
456- w.StructType closureStruct = _makeClosureStruct (
457- closureName, vtableStruct, parent? .closureStruct ?? closureBaseStruct);
490+ (typeCount == 0 ? nonGenericVtableBaseStruct : genericVtableBaseStruct);
491+ w.StructType vtableStruct =
492+ _defineStruct (vtableName, superType: parentVtableStruct);
493+
494+ // Define a new struct type for the closure, extending [closureBaseStruct]
495+ // directly or indirectly, and install a new vtable struct (which is a
496+ // subtype of the vtable struct of the [closureBaseStruct]).
497+ final closureStructSuper = parent? .closureStruct ?? closureBaseStruct;
498+ assert (closureStructSuper.isSubtypeOf (closureBaseStruct));
499+ final closureStruct =
500+ _defineStruct (closureName, superType: closureStructSuper);
501+ assert (closureStruct.fieldNames[3 ] == 'vtable' );
502+ closureStruct.fields[3 ] = w.FieldType (
503+ w.RefType .def (vtableStruct, nullable: false ),
504+ mutable: false );
458505
459506 ClosureRepresentation ? instantiatedRepresentation;
460507 w.StructType ? instantiationContextStruct;
@@ -476,7 +523,9 @@ class ClosureLayouter extends RecursiveVisitor {
476523 if (parent == null ) {
477524 assert (vtableStruct.fields.length ==
478525 FieldIndex .vtableInstantiationFunction);
526+ final index = vtableStruct.fields.length;
479527 vtableStruct.fields.add (functionFieldType);
528+ vtableStruct.fieldNames[index] = 'instantiateGenericClosureFun' ;
480529 } else {
481530 vtableStruct.fields[FieldIndex .vtableInstantiationFunction] =
482531 functionFieldType;
@@ -505,8 +554,11 @@ class ClosureLayouter extends RecursiveVisitor {
505554 ], [
506555 topType
507556 ]);
557+ final index = vtableStruct.fields.length;
508558 vtableStruct.fields.add (
509559 w.FieldType (w.RefType .def (entry, nullable: false ), mutable: false ));
560+ vtableStruct.fieldNames[index] =
561+ 'closureCallEntry-$typeCount -$paramCount ' ;
510562 }
511563
512564 ClosureRepresentation representation = ClosureRepresentation (
0 commit comments