Skip to content

Commit 85ccbe6

Browse files
rakudramaCommit Queue
authored andcommitted
[dart2js] late final initialized instance field getters are idempotent
I wanted to detect that the synthesized getter is a late final field getter and set the 'allowCSE' property in the optimizer, but as there is not obvious predicate, used the annotation instead. Change-Id: Idd8797e3e7e8ececabe57e57e10c3fb9ade71477 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430921 Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Stephen Adams <[email protected]> Reviewed-by: Nate Biggs <[email protected]>
1 parent 28fc634 commit 85ccbe6

File tree

7 files changed

+57
-13
lines changed

7 files changed

+57
-13
lines changed

pkg/compiler/lib/src/kernel/transformations/modular/late_lowering.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ class LateLowering {
7676

7777
final ExtensionTable _extensionTable = ExtensionTable();
7878

79+
late final InstanceConstant pragmaAllowCSE = _pragmaConstant(
80+
'dart2js:allow-cse',
81+
);
82+
7983
LateLowering(this._coreTypes, CompilerOptions? _options)
8084
: _omitLateNames = _options?.omitLateNames ?? false,
8185
_readLocal = _Reader(_coreTypes.cellReadLocal),
@@ -674,6 +678,12 @@ class LateLowering {
674678
// transformer flags to reflect whether the getter contains super calls.
675679
getter.transformerFlags = field.transformerFlags;
676680
_copyAnnotations(getter, field);
681+
if (initializer != null && field.isFinal) {
682+
getter.addAnnotation(
683+
ConstantExpression(pragmaAllowCSE, _coreTypes.pragmaNonNullableRawType)
684+
..fileOffset = field.fileOffset,
685+
);
686+
}
677687
enclosingClass.addProcedure(getter);
678688

679689
VariableDeclaration setterValue = VariableDeclaration(
@@ -750,6 +760,13 @@ class LateLowering {
750760
}
751761
}
752762

763+
InstanceConstant _pragmaConstant(String pragmaName) {
764+
return InstanceConstant(_coreTypes.pragmaClass.reference, [], {
765+
_coreTypes.pragmaName.fieldReference: StringConstant(pragmaName),
766+
_coreTypes.pragmaOptions.fieldReference: NullConstant(),
767+
});
768+
}
769+
753770
TreeNode transformField(Field field, Member contextMember) {
754771
_contextMember = contextMember;
755772

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7873,11 +7873,19 @@ class KernelSsaGraphBuilder extends ir.VisitorDefault<void>
78737873
return false;
78747874
}
78757875

7876-
// Don't inline functions marked with 'allow-cse' and 'allow-dce' since we
7877-
// need the call instruction to do these optimizations. We might be able to
7876+
// Don't inline functions marked with 'allow-dce' since we need the call
7877+
// instruction to recognize the whole call as unused. We might be able to
78787878
// inline simple methods afterwards.
7879-
if (closedWorld.annotationsData.allowCSE(function) ||
7880-
closedWorld.annotationsData.allowDCE(function)) {
7879+
if (closedWorld.annotationsData.allowDCE(function)) {
7880+
return false;
7881+
}
7882+
7883+
// Don't inline functions marked with 'allow-cse' since we need the call
7884+
// instructions to recognize repeated calls. We might be able to inline
7885+
// simple methods afterwards. If this is the only call site, we will never
7886+
// find the repeated call, so we should consider inlining here.
7887+
if (closedWorld.annotationsData.allowCSE(function) &&
7888+
!_isCalledOnce(function)) {
78817889
return false;
78827890
}
78837891

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,6 +1344,9 @@ abstract class HInstruction implements SpannableWithEntity {
13441344
bool hasSameType = typeEquals(other);
13451345
assert(hasSameType == (_gvnType == other._gvnType));
13461346
if (!hasSameType) return false;
1347+
// Check the data first to ensure we are considering the same element or
1348+
// selector.
1349+
if (!dataEquals(other)) return false;
13471350
assert((useGvn() && other.useGvn()) || (allowCSE && other.allowCSE));
13481351
if (sideEffects != other.sideEffects) return false;
13491352
// Check that the inputs match.
@@ -1355,8 +1358,7 @@ abstract class HInstruction implements SpannableWithEntity {
13551358
return false;
13561359
}
13571360
}
1358-
// Check that the data in the instruction matches.
1359-
return dataEquals(other);
1361+
return true;
13601362
}
13611363

13621364
int gvnHashCode() {
@@ -2092,13 +2094,8 @@ abstract class HInvokeDynamic extends HInvoke implements InstructionContext {
20922094

20932095
@override
20942096
bool dataEquals(HInvokeDynamic other) {
2095-
// Use the name and the kind instead of [Selector.operator==]
2096-
// because we don't need to check the arity (already checked in
2097-
// [gvnEquals]), and the receiver types may not be in sync.
2098-
// TODO(sra): If we GVN calls with named (optional) arguments then the
2099-
// selector needs a deeper check for the same subset of named arguments.
2100-
return selector.name == other.selector.name &&
2101-
selector.kind == other.selector.kind;
2097+
return selector == other.selector &&
2098+
(useGvn() == other.useGvn() || allowCSE == other.allowCSE);
21022099
}
21032100
}
21042101

pkg/front_end/testcases/dart2js/late_fields.dart.strong.transformed.expect

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class C extends core::Object {
3232
}
3333
set c(synthesized core::int value) → void
3434
this.{self::C::_#C#c#AI} = value;
35+
@#C3
3536
get d() → core::int {
3637
synthesized core::int value = this.{self::C::_#C#d#FI}{core::int};
3738
if(_in::isSentinel(value)) {
@@ -68,6 +69,11 @@ static method testInitializedFinalInstanceField() → void {
6869
core::print(self::c.{self::C::d}{core::int});
6970
}
7071

72+
constants {
73+
#C1 = "dart2js:allow-cse"
74+
#C2 = null
75+
#C3 = core::pragma {name:#C1, options:#C2}
76+
}
7177

7278
Extra constant evaluation status:
7379
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_fields.dart:15:16 -> DoubleConstant(-1.0)

pkg/front_end/testcases/dart2js/late_fields_with_annotation.dart.strong.transformed.expect

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class C extends core::Object {
4242
this.{self::C::_#C#c#AI} = value;
4343
@#C5
4444
@#C9
45+
@#C11
4546
get d() → core::int {
4647
synthesized core::int value = this.{self::C::_#C#d#FI}{core::int};
4748
if(_in::isSentinel(value)) {
@@ -88,6 +89,8 @@ constants {
8889
#C7 = core::pragma {name:#C6, options:#C2}
8990
#C8 = "dart2js:noInline"
9091
#C9 = core::pragma {name:#C8, options:#C2}
92+
#C10 = "dart2js:allow-cse"
93+
#C11 = core::pragma {name:#C10, options:#C2}
9194
}
9295

9396
Extra constant evaluation status:

pkg/front_end/testcases/dart2js/late_from_dill/main.dart.strong.expect

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class C extends core::Object {
119119
}
120120
set c(synthesized core::int value) → void
121121
this.{mai::C::_#C#c#AI} = value;
122+
@#C3
122123
get d() → core::int {
123124
synthesized core::int value = this.{mai::C::_#C#d#FI}{core::int};
124125
if(_in::isSentinel(value)) {
@@ -212,3 +213,9 @@ static get b() → core::int
212213
return mai2::_#b.{_la::_Cell::readField}<core::int>(){() → core::int};
213214
static set b(synthesized core::int value) → void
214215
return mai2::_#b.{_la::_Cell::finalFieldValue} = value;
216+
217+
constants {
218+
#C1 = "dart2js:allow-cse"
219+
#C2 = null
220+
#C3 = core::pragma {name:#C1, options:#C2}
221+
}

pkg/front_end/testcases/dart2js/late_from_dill/main.dart.strong.transformed.expect

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class C extends core::Object {
119119
}
120120
set c(synthesized core::int value) → void
121121
this.{mai::C::_#C#c#AI} = value;
122+
@#C3
122123
get d() → core::int {
123124
synthesized core::int value = this.{mai::C::_#C#d#FI}{core::int};
124125
if(_in::isSentinel(value)) {
@@ -213,6 +214,11 @@ static get b() → core::int
213214
static set b(synthesized core::int value) → void
214215
return mai2::_#b.{_la::_Cell::finalFieldValue} = value;
215216

217+
constants {
218+
#C1 = "dart2js:allow-cse"
219+
#C2 = null
220+
#C3 = core::pragma {name:#C1, options:#C2}
221+
}
216222

217223
Extra constant evaluation status:
218224
Evaluated: InstanceInvocation @ org-dartlang-testcase:///main_lib1.dart:8:16 -> DoubleConstant(-1.0)

0 commit comments

Comments
 (0)