Skip to content

Commit 33bdacc

Browse files
osa1Commit Queue
authored andcommitted
[dart2wasm] Refactor ParameterInfo
- Remove the `Member? member` field: - Knowing a `ParameterInfo`s member is not too useful, because it doesn't tell us for which use of the member (tear-off getter, invocation) the `ParameterInfo` is for. - The `member` field has two uses: - To compute whether the function being called takes a receiver or context parameter. - In dispatch table builder: to check whether a selector (via its `ParameterInfo`) is for `noSuchMethod`. Both of these can be implemented more directly, as done in this CL: - Add `final bool takesContextOrReceiver` member to `ParameterInfo`. - Add `final bool alwaysAddToDispatchTable` member to `SelectorInfo` to handle the special case with `noSuchMethod`. - Add various assertions in `ParameterInfo` members. Change-Id: I473657f594c6306605677cf001854407d43f1347 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/398883 Reviewed-by: Martin Kustermann <[email protected]> Commit-Queue: Ömer Ağacan <[email protected]>
1 parent 1b8e01f commit 33bdacc

File tree

3 files changed

+64
-54
lines changed

3 files changed

+64
-54
lines changed

pkg/dart2wasm/lib/dispatch_table.dart

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,16 @@ class SelectorInfo {
7070
int? offset;
7171

7272
/// The selector's member's name.
73-
String get name => paramInfo.member!.name.text;
73+
final String name;
7474

75-
SelectorInfo._(this.translator, this.id, this.callCount, this.paramInfo,
76-
{required this.isSetter});
75+
/// Whether the selector is for `Object.noSuchMethod`. We introduce instance
76+
/// invocations of `noSuchMethod` in dynamic calls, so we always add
77+
/// `noSuchMethod` overrides to the dispatch table.
78+
final bool isNoSuchMethod;
79+
80+
SelectorInfo._(
81+
this.translator, this.id, this.name, this.callCount, this.paramInfo,
82+
{required this.isSetter, required this.isNoSuchMethod});
7783

7884
/// Compute the signature for the functions implementing members targeted by
7985
/// this selector.
@@ -285,9 +291,10 @@ class DispatchTable {
285291

286292
final selector = _selectorInfo.putIfAbsent(
287293
selectorId,
288-
() => SelectorInfo._(translator, selectorId,
294+
() => SelectorInfo._(translator, selectorId, member.name.text,
289295
_selectorMetadata[selectorId].callCount, paramInfo,
290-
isSetter: isSetter));
296+
isSetter: isSetter,
297+
isNoSuchMethod: member == translator.objectNoSuchMethod));
291298
assert(selector.isSetter == isSetter);
292299
selector.hasTearOffUses |= metadata.hasTearOffUses;
293300
selector.hasNonThisUses |= metadata.hasNonThisUses;
@@ -452,10 +459,7 @@ class DispatchTable {
452459
// Assign selector offsets
453460

454461
bool isUsedViaDispatchTableCall(SelectorInfo selector) {
455-
// Special case for `objectNoSuchMethod`: we introduce instance
456-
// invocations of `objectNoSuchMethod` in dynamic calls, so keep it alive
457-
// even if there was no references to it from the Dart code.
458-
if (selector.paramInfo.member! == translator.objectNoSuchMethod) {
462+
if (selector.isNoSuchMethod) {
459463
return true;
460464
}
461465
if (selector.callCount == 0) return false;

pkg/dart2wasm/lib/param_info.dart

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,22 @@ import 'reference_extensions.dart';
99
/// Information about optional parameters and their default values for a member
1010
/// or a set of members belonging to the same override group.
1111
class ParameterInfo {
12-
final Member? member;
13-
int typeParamCount = 0;
12+
final int typeParamCount;
1413

1514
/// Default values of optional positonal parameters. `positional[i] == null`
1615
/// means positional parameter `i` is not optional.
17-
late final List<Constant?> positional;
16+
final List<Constant?> positional;
1817

1918
/// Default values of named parameters. Similar to [positional], `null` means
2019
/// the the parameter is not optional.
21-
late final Map<String, Constant?> named;
20+
final Map<String, Constant?> named;
2221

23-
// Do not access these until the info is complete.
22+
final bool takesContextOrReceiver;
23+
24+
// Dispatch table builder updates `ParameterInfo`s, do not access late fields
25+
// until the `ParameterInfo` is complete.
2426
late final List<String> names = named.keys.toList()..sort();
27+
2528
late final Map<String, int> nameIndex = {
2629
for (int i = 0; i < names.length; i++) names[i]: positional.length + i
2730
};
@@ -45,47 +48,66 @@ class ParameterInfo {
4548
}
4649
}
4750

48-
ParameterInfo.fromMember(Reference target) : member = target.asMember {
49-
FunctionNode? function = member!.function;
51+
ParameterInfo._(this.takesContextOrReceiver, this.typeParamCount,
52+
this.positional, this.named);
53+
54+
factory ParameterInfo.fromMember(Reference target) {
55+
final member = target.asMember; // Constructor, Field, or Procedure
56+
final function = member.function;
57+
5058
if (target.isTearOffReference) {
51-
positional = [];
52-
named = {};
53-
} else if (function != null) {
54-
typeParamCount = (member is Constructor
55-
? member!.enclosingClass!.typeParameters
59+
// Tear-off getters don't take type parameters even if the member is
60+
// generic.
61+
return ParameterInfo._(true, 0, [], {});
62+
}
63+
64+
if (function != null) {
65+
// Constructor, or static or instance method.
66+
assert(member is Constructor || member is Procedure);
67+
68+
final typeParamCount = (member is Constructor
69+
? member.enclosingClass.typeParameters
5670
: function.typeParameters)
5771
.length;
58-
positional = List.generate(function.positionalParameters.length, (i) {
72+
73+
final positional =
74+
List.generate(function.positionalParameters.length, (i) {
5975
// A required parameter has no default value.
6076
if (i < function.requiredParameterCount) return null;
6177
return _defaultValue(function.positionalParameters[i]);
6278
});
63-
named = {
79+
80+
final named = {
6481
for (VariableDeclaration param in function.namedParameters)
6582
param.name!: _defaultValue(param)
6683
};
67-
} else {
68-
// A setter parameter has no default value.
69-
positional = [if (target.isSetter) null];
70-
named = {};
84+
85+
return ParameterInfo._(
86+
member.isInstanceMember, typeParamCount, positional, named);
7187
}
88+
89+
// A setter or getter. A setter parameter has no default value.
90+
assert(member is Field);
91+
return ParameterInfo._(true, 0, [if (target.isSetter) null], {});
7292
}
7393

74-
ParameterInfo.fromLocalFunction(FunctionNode function) : member = null {
75-
typeParamCount = function.typeParameters.length;
76-
positional = List.generate(function.positionalParameters.length, (i) {
94+
factory ParameterInfo.fromLocalFunction(FunctionNode function) {
95+
final typeParamCount = function.typeParameters.length;
96+
final positional = List.generate(function.positionalParameters.length, (i) {
7797
// A required parameter has no default value.
7898
if (i < function.requiredParameterCount) return null;
7999
return _defaultValue(function.positionalParameters[i]);
80100
});
81-
named = {
101+
final named = {
82102
for (VariableDeclaration param in function.namedParameters)
83103
param.name!: _defaultValue(param)
84104
};
105+
return ParameterInfo._(true, typeParamCount, positional, named);
85106
}
86107

87108
void merge(ParameterInfo other) {
88109
assert(typeParamCount == other.typeParamCount);
110+
assert(takesContextOrReceiver == other.takesContextOrReceiver);
89111
for (int i = 0; i < other.positional.length; i++) {
90112
if (i >= positional.length) {
91113
positional.add(other.positional[i]);

pkg/dart2wasm/lib/translator.dart

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -724,11 +724,6 @@ class Translator with KernelNodes {
724724
ClosureImplementation getClosure(FunctionNode functionNode,
725725
w.BaseFunction target, ParameterInfo paramInfo, String name) {
726726
final targetModule = target.enclosingModule;
727-
// The target function takes an extra initial parameter if it's a function
728-
// expression / local function (which takes a context) or a tear-off of an
729-
// instance method (which takes a receiver).
730-
bool takesContextOrReceiver =
731-
paramInfo.member == null || paramInfo.member!.isInstanceMember;
732727

733728
// Look up the closure representation for the signature.
734729
int typeCount = functionNode.typeParameters.length;
@@ -741,7 +736,7 @@ class Translator with KernelNodes {
741736
assert(positionalCount <= paramInfo.positional.length);
742737
assert(names.length <= paramInfo.named.length);
743738
assert(target.type.inputs.length ==
744-
(takesContextOrReceiver ? 1 : 0) +
739+
(paramInfo.takesContextOrReceiver ? 1 : 0) +
745740
paramInfo.typeParamCount +
746741
paramInfo.positional.length +
747742
paramInfo.named.length);
@@ -805,7 +800,7 @@ class Translator with KernelNodes {
805800
compilationQueue.add(CompilationTask(
806801
trampoline,
807802
_ClosureTrampolineGenerator(this, trampoline, target, typeCount,
808-
posArgCount, argNames, paramInfo, takesContextOrReceiver)));
803+
posArgCount, argNames, paramInfo)));
809804
return trampoline;
810805
}
811806

@@ -1394,25 +1389,17 @@ class _ClosureTrampolineGenerator implements CodeGenerator {
13941389
final int posArgCount;
13951390
final List<String> argNames;
13961391
final ParameterInfo paramInfo;
1397-
final bool takesContextOrReceiver;
1398-
1399-
_ClosureTrampolineGenerator(
1400-
this.translator,
1401-
this.trampoline,
1402-
this.target,
1403-
this.typeCount,
1404-
this.posArgCount,
1405-
this.argNames,
1406-
this.paramInfo,
1407-
this.takesContextOrReceiver);
1392+
1393+
_ClosureTrampolineGenerator(this.translator, this.trampoline, this.target,
1394+
this.typeCount, this.posArgCount, this.argNames, this.paramInfo);
14081395

14091396
@override
14101397
void generate(w.InstructionsBuilder b, List<w.Local> paramLocals,
14111398
w.Label? returnLabel) {
14121399
assert(returnLabel == null);
14131400

14141401
int targetIndex = 0;
1415-
if (takesContextOrReceiver) {
1402+
if (paramInfo.takesContextOrReceiver) {
14161403
w.Local receiver = trampoline.locals[0];
14171404
b.local_get(receiver);
14181405
translator.convertType(
@@ -1478,9 +1465,6 @@ class _ClosureDynamicEntryGenerator implements CodeGenerator {
14781465

14791466
final b = function.body;
14801467

1481-
final bool takesContextOrReceiver =
1482-
paramInfo.member == null || paramInfo.member!.isInstanceMember;
1483-
14841468
final int typeCount = functionNode.typeParameters.length;
14851469

14861470
final closureLocal = function.locals[0];
@@ -1500,7 +1484,7 @@ class _ClosureDynamicEntryGenerator implements CodeGenerator {
15001484
int inputIdx = 0;
15011485

15021486
// Push context or receiver
1503-
if (takesContextOrReceiver) {
1487+
if (paramInfo.takesContextOrReceiver) {
15041488
final closureBaseType = w.RefType.def(
15051489
translator.closureLayouter.closureBaseStruct,
15061490
nullable: false);

0 commit comments

Comments
 (0)