Skip to content

Commit e2fdf18

Browse files
rakudramaCommit Queue
authored andcommitted
[dart2js] Refine types based on test with late sentinel
A small number of getters for `late final` instance fields with initializers have better code. When the initializing expression provably does not write to the backing field*, the field value is re-used rather than re-loaded for the 'final' check (that the field has not been assigned during the evaluation of the initializer). We are testing both `value === $` and `value !== $`: ``` value = _this.___LayoutWidgetState_firstChild_FI; if (value === $) { result = A._LayoutWidgetState__buildChild(B.ValueKey_1, _this._widget.node.firstChild); value !== $ && A.throwUnnamedLateFieldADI(); _this.___LayoutWidgetState_firstChild_FI = result; value = result; } ``` In this change we refine the type of the tested value to late sentinel, allowing the check to be removed: ``` if (value === $) value = _this.___LayoutWidgetState_firstChild_FI = A._LayoutWidgetState__buildChild(B.ValueKey_1, _this._widget.node.firstChild); ``` *This effect analysis is pretty simple ('writes some field'), but if improved, we might expect more `late final` getters to benefit. Change-Id: I444ed157083663b848fb2f115d0575e544b47727 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430962 Reviewed-by: Mayank Patke <[email protected]> Commit-Queue: Stephen Adams <[email protected]>
1 parent 8955223 commit e2fdf18

File tree

1 file changed

+55
-28
lines changed

1 file changed

+55
-28
lines changed

pkg/compiler/lib/src/ssa/optimize.dart

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4100,7 +4100,7 @@ class SsaCodeMotion extends HBaseVisitor<void> implements OptimizationPhase {
41004100
class SsaTypeConversionInserter extends HBaseVisitor<void>
41014101
implements OptimizationPhase {
41024102
@override
4103-
final String name = "SsaTypeconversionInserter";
4103+
final String name = "SsaTypeConversionInserter";
41044104
final JClosedWorld closedWorld;
41054105

41064106
SsaTypeConversionInserter(this.closedWorld);
@@ -4116,16 +4116,16 @@ class SsaTypeConversionInserter extends HBaseVisitor<void>
41164116
@override
41174117
bool validPostcondition(HGraph graph) => true;
41184118

4119-
// Update users of [input] that are dominated by [:dominator.first:]
4120-
// to use [TypeKnown] of [input] instead. As the type information depends
4121-
// on the control flow, we mark the inserted [HTypeKnown] nodes as
4122-
// non-movable.
4123-
void insertTypePropagationForDominatedUsers(
4119+
/// Update users of [value] that are dominated by the start of the [dominator]
4120+
/// block to use [TypeKnown] of [value] instead. As the type refinement
4121+
/// depends on the control flow, we mark the inserted [HTypeKnown] nodes as
4122+
/// non-movable.
4123+
void insertTypeRefinement(
41244124
HBasicBlock dominator,
4125-
HInstruction input,
4125+
HInstruction value,
41264126
AbstractValue convertedType,
41274127
) {
4128-
DominatedUses dominatedUses = DominatedUses.of(input, dominator.first!);
4128+
DominatedUses dominatedUses = DominatedUses.of(value, dominator.first!);
41294129
if (dominatedUses.isEmpty) return;
41304130

41314131
// Check to avoid adding a duplicate HTypeKnown node.
@@ -4134,51 +4134,59 @@ class SsaTypeConversionInserter extends HBaseVisitor<void>
41344134
if (user is HTypeKnown &&
41354135
user.isPinned &&
41364136
user.knownType == convertedType &&
4137-
user.checkedInput == input) {
4137+
user.checkedInput == value) {
41384138
return;
41394139
}
41404140
}
41414141

4142-
HTypeKnown newInput = HTypeKnown.pinned(convertedType, input);
4143-
dominator.addBefore(dominator.first, newInput);
4144-
dominatedUses.replaceWith(newInput);
4142+
final replacement = HTypeKnown.pinned(convertedType, value);
4143+
dominator.addBefore(dominator.first, replacement);
4144+
dominatedUses.replaceWith(replacement);
4145+
}
4146+
4147+
void insertTypeRefinements(
4148+
List<HBasicBlock> targets,
4149+
HInstruction value,
4150+
AbstractValue convertedType,
4151+
) {
4152+
for (final block in targets) {
4153+
insertTypeRefinement(block, value, convertedType);
4154+
}
41454155
}
41464156

41474157
@override
41484158
void visitIsTest(HIsTest node) {
4159+
HInstruction input = node.checkedInput;
4160+
if (input.usedBy.length <= 1) return; // No other uses to refine.
4161+
41494162
List<HBasicBlock> trueTargets = [];
41504163
List<HBasicBlock> falseTargets = [];
41514164

41524165
collectTargets(node, trueTargets, falseTargets);
41534166

41544167
if (trueTargets.isEmpty && falseTargets.isEmpty) return;
41554168

4156-
AbstractValue convertedType = node.checkedAbstractValue.abstractValue;
4157-
HInstruction input = node.checkedInput;
4158-
4159-
for (HBasicBlock block in trueTargets) {
4160-
insertTypePropagationForDominatedUsers(block, input, convertedType);
4161-
}
4169+
AbstractValue whenTrueType = node.checkedAbstractValue.abstractValue;
4170+
insertTypeRefinements(trueTargets, input, whenTrueType);
41624171
// TODO(sra): Also strengthen uses for when the condition is precise and
41634172
// known false (e.g. int? x; ... if (x is! int) use(x)). Avoid strengthening
41644173
// to `null`.
41654174
}
41664175

41674176
@override
41684177
void visitIsTestSimple(HIsTestSimple node) {
4178+
HInstruction input = node.checkedInput;
4179+
if (input.usedBy.length <= 1) return; // No other uses to refine.
4180+
41694181
List<HBasicBlock> trueTargets = [];
41704182
List<HBasicBlock> falseTargets = [];
41714183

41724184
collectTargets(node, trueTargets, falseTargets);
41734185

41744186
if (trueTargets.isEmpty && falseTargets.isEmpty) return;
41754187

4176-
AbstractValue convertedType = node.checkedAbstractValue.abstractValue;
4177-
HInstruction input = node.checkedInput;
4178-
4179-
for (HBasicBlock block in trueTargets) {
4180-
insertTypePropagationForDominatedUsers(block, input, convertedType);
4181-
}
4188+
AbstractValue whenTrueType = node.checkedAbstractValue.abstractValue;
4189+
insertTypeRefinements(trueTargets, input, whenTrueType);
41824190
// TODO(sra): Also strengthen uses for when the condition is precise and
41834191
// known false (e.g. int? x; ... if (x is! int) use(x)). Avoid strengthening
41844192
// to `null`.
@@ -4199,6 +4207,8 @@ class SsaTypeConversionInserter extends HBaseVisitor<void>
41994207
return;
42004208
}
42014209

4210+
if (input.usedBy.length <= 1) return; // No other uses to refine.
4211+
42024212
if (_abstractValueDomain.isNull(input.instructionType).isDefinitelyFalse) {
42034213
return;
42044214
}
@@ -4213,15 +4223,32 @@ class SsaTypeConversionInserter extends HBaseVisitor<void>
42134223
AbstractValue nonNullType = _abstractValueDomain.excludeNull(
42144224
input.instructionType,
42154225
);
4216-
4217-
for (HBasicBlock block in falseTargets) {
4218-
insertTypePropagationForDominatedUsers(block, input, nonNullType);
4219-
}
4226+
insertTypeRefinements(falseTargets, input, nonNullType);
42204227
// We don't strengthen the known-true references. It doesn't happen often
42214228
// and we don't want "if (x==null) return x;" to convert between JavaScript
42224229
// 'null' and 'undefined'.
42234230
}
42244231

4232+
@override
4233+
void visitIsLateSentinel(HIsLateSentinel node) {
4234+
final input = node.inputs.single;
4235+
if (input.usedBy.length <= 1) return; // No other uses to refine.
4236+
4237+
List<HBasicBlock> trueTargets = [];
4238+
List<HBasicBlock> falseTargets = [];
4239+
4240+
collectTargets(node, trueTargets, falseTargets);
4241+
4242+
if (trueTargets.isEmpty && falseTargets.isEmpty) return;
4243+
4244+
final sentinelType = _abstractValueDomain.lateSentinelType;
4245+
final nonSentinelType = _abstractValueDomain.excludeLateSentinel(
4246+
input.instructionType,
4247+
);
4248+
insertTypeRefinements(trueTargets, input, sentinelType);
4249+
insertTypeRefinements(falseTargets, input, nonSentinelType);
4250+
}
4251+
42254252
void collectTargets(
42264253
HInstruction instruction,
42274254
List<HBasicBlock>? trueTargets,

0 commit comments

Comments
 (0)