Skip to content

Commit f56b0f6

Browse files
alexmarkovcommit-bot@chromium.org
authored andcommitted
[vm/aot/tfa] Whole-program constant propagation
Size: flutter_gallery total size -2.48% (arm), -2.3% (arm64) flutter_gallery instructions size -2.91% (arm), -2.77% (arm64) velocity_tracker_bench total size -7.5% (arm), -7.1% (arm64) Performance: SkeletalAnimation +46.02% (Intel Core i5), +37.75% (Intel Xeon), +24.86% (arm), +39.75% (arm64). FfiMemory.Pointer* +44-64% (x64) FfiMemory.PointerPointer +436-465% (x64), +443% (arm64). Issue: #37710 Change-Id: I6221bfa02b165ccc17d4ee8b857bb89212febaff Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/125936 Reviewed-by: Régis Crelier <regis@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
1 parent 9929b53 commit f56b0f6

File tree

54 files changed

+594
-174
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+594
-174
lines changed

pkg/kernel/lib/ast.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7104,6 +7104,7 @@ abstract class BinarySink {
71047104
void writeStringReference(String str);
71057105
void writeName(Name node);
71067106
void writeDartType(DartType type);
7107+
void writeConstantReference(Constant constant);
71077108
void writeNode(Node node);
71087109

71097110
void enterScope(
@@ -7132,6 +7133,7 @@ abstract class BinarySource {
71327133
String readStringReference();
71337134
Name readName();
71347135
DartType readDartType();
7136+
Constant readConstantReference();
71357137
FunctionNode readFunctionNode();
71367138

71377139
void enterScope({List<TypeParameter> typeParameters});

pkg/kernel/lib/target/targets.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ abstract class Target {
264264
Class concreteConstMapLiteralClass(CoreTypes coreTypes) => null;
265265

266266
Class concreteIntLiteralClass(CoreTypes coreTypes, int value) => null;
267+
Class concreteDoubleLiteralClass(CoreTypes coreTypes, double value) => null;
267268
Class concreteStringLiteralClass(CoreTypes coreTypes, String value) => null;
268269

269270
ConstantsBackend constantsBackend(CoreTypes coreTypes);

pkg/vm/lib/bytecode/gen_bytecode.dart

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,8 +1285,7 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
12851285
throw 'Expected constant, got ${expr.runtimeType}';
12861286
}
12871287

1288-
void _genPushConstExpr(Expression expr) {
1289-
final constant = _getConstant(expr);
1288+
void _genPushConstant(Constant constant) {
12901289
if (constant is NullConstant) {
12911290
asm.emitPushNull();
12921291
} else if (constant is BoolConstant) {
@@ -1298,6 +1297,20 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
12981297
}
12991298
}
13001299

1300+
void _genPushConstExpr(Expression expr) {
1301+
if (expr is ConstantExpression) {
1302+
_genPushConstant(expr.constant);
1303+
} else if (expr is NullLiteral) {
1304+
asm.emitPushNull();
1305+
} else if (expr is BoolLiteral) {
1306+
_genPushBool(expr.value);
1307+
} else if (expr is IntLiteral) {
1308+
_genPushInt(expr.value);
1309+
} else {
1310+
_genPushConstant(_getConstant(expr));
1311+
}
1312+
}
1313+
13011314
void _genReturnTOS([int yieldSourcePosition = null]) {
13021315
if (options.causalAsyncStacks &&
13031316
parentFunction != null &&
@@ -1340,6 +1353,9 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
13401353
} else {
13411354
asm.emitDirectCall(cpIndex, totalArgCount);
13421355
}
1356+
if (inferredTypeMetadata != null && node != null) {
1357+
_replaceWithConstantValue(node);
1358+
}
13431359
}
13441360

13451361
void _genDirectCallWithArgs(Member target, Arguments args,
@@ -1794,7 +1810,20 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
17941810
} else {
17951811
inferredTypesAttribute.add(NullConstant());
17961812
}
1797-
inferredTypesAttribute.add(IntConstant(md.flags));
1813+
// Inferred constant values are handled in bytecode generator
1814+
// (_replaceWithConstantValue, _initConstantParameters) and
1815+
// not propagated to VM.
1816+
final flags = md.flags & ~InferredType.flagConstant;
1817+
inferredTypesAttribute.add(IntConstant(flags));
1818+
}
1819+
1820+
void _replaceWithConstantValue(TreeNode node) {
1821+
final InferredType md = inferredTypeMetadata[node];
1822+
if (md == null || md.constantValue == null || asm.isUnreachable) {
1823+
return;
1824+
}
1825+
asm.emitDrop1();
1826+
_genPushConstant(md.constantValue);
17981827
}
17991828

18001829
// Generate additional code for 'operator ==' to handle nulls.
@@ -2030,6 +2059,10 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
20302059
asm.emitPopLocal(locals.functionTypeArgsVarIndexInFrame);
20312060
}
20322061
}
2062+
2063+
if (inferredTypeMetadata != null && function != null) {
2064+
_initConstantParameters(function);
2065+
}
20332066
}
20342067

20352068
void _handleDelayedTypeArguments(Label doneCheckingTypeArguments) {
@@ -2073,6 +2106,21 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
20732106
asm.emitPopLocal(locals.functionTypeArgsVarIndexInFrame);
20742107
}
20752108

2109+
void _initConstantParameters(FunctionNode function) {
2110+
function.positionalParameters.forEach(_initParameterIfConstant);
2111+
locals.sortedNamedParameters.forEach(_initParameterIfConstant);
2112+
}
2113+
2114+
void _initParameterIfConstant(VariableDeclaration variable) {
2115+
final md = inferredTypeMetadata[variable];
2116+
if (md != null && md.constantValue != null) {
2117+
_genPushConstant(md.constantValue);
2118+
asm.emitPopLocal(locals.isCaptured(variable)
2119+
? locals.getOriginalParamSlotIndex(variable)
2120+
: locals.getVarIndexInFrame(variable));
2121+
}
2122+
}
2123+
20762124
void _setupInitialContext(FunctionNode function) {
20772125
_allocateContextIfNeeded();
20782126

@@ -3279,25 +3327,32 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
32793327
_appendInferredType(node, asm.offset);
32803328
}
32813329

3330+
bool generated = false;
32823331
if (invocationKind != InvocationKind.getter && !isDynamic && !isUnchecked) {
32833332
final staticReceiverType = getStaticType(receiver, staticTypeContext);
32843333
if (isInstantiatedInterfaceCall(interfaceTarget, staticReceiverType)) {
32853334
final callCpIndex = cp.addInstantiatedInterfaceCall(
32863335
invocationKind, interfaceTarget, argDesc, staticReceiverType);
32873336
asm.emitInstantiatedInterfaceCall(callCpIndex, totalArgCount);
3288-
return;
3337+
generated = true;
32893338
}
32903339
}
32913340

3292-
final callCpIndex = cp.addInstanceCall(
3293-
invocationKind, interfaceTarget, targetName, argDesc);
3294-
if (isDynamic) {
3295-
assert(!isUnchecked);
3296-
asm.emitDynamicCall(callCpIndex, totalArgCount);
3297-
} else if (isUnchecked) {
3298-
asm.emitUncheckedInterfaceCall(callCpIndex, totalArgCount);
3299-
} else {
3300-
asm.emitInterfaceCall(callCpIndex, totalArgCount);
3341+
if (!generated) {
3342+
final callCpIndex = cp.addInstanceCall(
3343+
invocationKind, interfaceTarget, targetName, argDesc);
3344+
if (isDynamic) {
3345+
assert(!isUnchecked);
3346+
asm.emitDynamicCall(callCpIndex, totalArgCount);
3347+
} else if (isUnchecked) {
3348+
asm.emitUncheckedInterfaceCall(callCpIndex, totalArgCount);
3349+
} else {
3350+
asm.emitInterfaceCall(callCpIndex, totalArgCount);
3351+
}
3352+
}
3353+
3354+
if (inferredTypeMetadata != null && node != null) {
3355+
_replaceWithConstantValue(node);
33013356
}
33023357
}
33033358

@@ -3619,6 +3674,13 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
36193674
if (target.isConst) {
36203675
_genPushConstExpr(target.initializer);
36213676
} else if (!_needsGetter(target)) {
3677+
if (inferredTypeMetadata != null) {
3678+
final InferredType md = inferredTypeMetadata[node];
3679+
if (md != null && md.constantValue != null) {
3680+
_genPushConstant(md.constantValue);
3681+
return;
3682+
}
3683+
}
36223684
asm.emitLoadStatic(cp.addStaticField(target));
36233685
} else {
36243686
_genDirectCall(target, objectTable.getArgDescHandle(0), 0,
@@ -4676,7 +4738,7 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
46764738

46774739
@override
46784740
visitConstantExpression(ConstantExpression node) {
4679-
_genPushConstExpr(node);
4741+
_genPushConstant(node.constant);
46804742
}
46814743
}
46824744

pkg/vm/lib/metadata/inferred_type.dart

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:kernel/ast.dart';
99
/// Metadata for annotating nodes with an inferred type information.
1010
class InferredType {
1111
final Reference _concreteClassReference;
12+
final Constant _constantValue;
1213
final int _flags;
1314

1415
static const int flagNullable = 1 << 0;
@@ -17,6 +18,8 @@ class InferredType {
1718
// For invocations: whether to use the unchecked entry-point.
1819
static const int flagSkipCheck = 1 << 2;
1920

21+
static const int flagConstant = 1 << 3;
22+
2023
// Entire list may be null if no type arguments were inferred.
2124
// Will always be null if `concreteClass` is null.
2225
//
@@ -27,22 +30,28 @@ class InferredType {
2730
// argument (in the runtime type) is always exactly a particular `DartType`.
2831
final List<DartType> exactTypeArguments;
2932

30-
InferredType(Class concreteClass, bool nullable, bool isInt,
33+
InferredType(
34+
Class concreteClass, bool nullable, bool isInt, Constant constantValue,
3135
{List<DartType> exactTypeArguments, bool skipCheck: false})
3236
: this._byReference(
3337
getClassReference(concreteClass),
38+
constantValue,
3439
(nullable ? flagNullable : 0) |
3540
(isInt ? flagInt : 0) |
36-
(skipCheck ? flagSkipCheck : 0),
41+
(skipCheck ? flagSkipCheck : 0) |
42+
(constantValue != null ? flagConstant : 0),
3743
exactTypeArguments);
3844

39-
InferredType._byReference(
40-
this._concreteClassReference, this._flags, this.exactTypeArguments) {
45+
InferredType._byReference(this._concreteClassReference, this._constantValue,
46+
this._flags, this.exactTypeArguments) {
4147
assert(exactTypeArguments == null || _concreteClassReference != null);
48+
assert(_constantValue == null || _concreteClassReference != null);
4249
}
4350

4451
Class get concreteClass => _concreteClassReference?.asClass;
4552

53+
Constant get constantValue => _constantValue;
54+
4655
bool get nullable => (_flags & flagNullable) != 0;
4756
bool get isInt => (_flags & flagInt) != 0;
4857
bool get skipCheck => (_flags & flagSkipCheck) != 0;
@@ -51,17 +60,30 @@ class InferredType {
5160

5261
@override
5362
String toString() {
54-
final base =
55-
"${concreteClass != null ? concreteClass : (isInt ? 'int' : '!')}";
56-
final suffix = "${nullable ? '?' : ''}";
57-
String typeArgs = "";
63+
final StringBuffer buf = new StringBuffer();
64+
if (concreteClass != null) {
65+
buf.write(concreteClass);
66+
} else if (isInt) {
67+
buf.write('int');
68+
} else {
69+
buf.write('!');
70+
}
71+
if (nullable) {
72+
buf.write('?');
73+
}
5874
if (exactTypeArguments != null) {
59-
typeArgs =
60-
exactTypeArguments.map((t) => t != null ? "$t" : "?").join(", ");
61-
typeArgs = "<" + typeArgs + ">";
75+
buf.write('<');
76+
buf.write(
77+
exactTypeArguments.map((t) => t != null ? "$t" : "?").join(", "));
78+
buf.write('>');
6279
}
63-
final skip = skipCheck ? " (skip check)" : "";
64-
return base + suffix + typeArgs + skip;
80+
if (skipCheck) {
81+
buf.write(' (skip check)');
82+
}
83+
if (_constantValue != null) {
84+
buf.write(' (value: $_constantValue)');
85+
}
86+
return buf.toString();
6587
}
6688
}
6789

@@ -82,6 +104,9 @@ class InferredTypeMetadataRepository extends MetadataRepository<InferredType> {
82104
sink.writeNullAllowedCanonicalNameReference(
83105
getCanonicalNameOfClass(metadata.concreteClass));
84106
sink.writeByte(metadata._flags);
107+
if (metadata.constantValue != null) {
108+
sink.writeConstantReference(metadata.constantValue);
109+
}
85110
}
86111

87112
@override
@@ -91,6 +116,10 @@ class InferredTypeMetadataRepository extends MetadataRepository<InferredType> {
91116
final concreteClassReference =
92117
source.readCanonicalNameReference()?.getReference();
93118
final flags = source.readByte();
94-
return new InferredType._byReference(concreteClassReference, flags, null);
119+
final constantValue = (flags & InferredType.flagConstant) != 0
120+
? source.readConstantReference()
121+
: null;
122+
return new InferredType._byReference(
123+
concreteClassReference, constantValue, flags, null);
95124
}
96125
}

pkg/vm/lib/target/vm.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class VmTarget extends Target {
4141
Class _oneByteString;
4242
Class _twoByteString;
4343
Class _smi;
44+
Class _double; // _Double, not double.
4445

4546
VmTarget(this.flags);
4647

@@ -423,6 +424,11 @@ class VmTarget extends Target {
423424
return null;
424425
}
425426

427+
@override
428+
Class concreteDoubleLiteralClass(CoreTypes coreTypes, double value) {
429+
return _double ??= coreTypes.index.getClass('dart:core', '_Double');
430+
}
431+
426432
@override
427433
Class concreteStringLiteralClass(CoreTypes coreTypes, String value) {
428434
const int maxLatin1 = 0xff;

0 commit comments

Comments
 (0)