Skip to content

Commit 3cb8ec8

Browse files
mkustermannCommit Queue
authored andcommitted
[dart2wasm] Assign field names to closure & vtable struct types
This makes it much easier to read code that accesses those fields. Change-Id: Ibbebf5c85e9e127adf6487704671f2973d61bda0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/456641 Reviewed-by: Ömer Ağacan <[email protected]> Reviewed-by: Nate Biggs <[email protected]> Commit-Queue: Martin Kustermann <[email protected]>
1 parent 820a1ec commit 3cb8ec8

File tree

1 file changed

+117
-65
lines changed

1 file changed

+117
-65
lines changed

pkg/dart2wasm/lib/closures.dart

Lines changed: 117 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)