Skip to content

Commit bd47ec2

Browse files
rakudramacommit-bot@chromium.org
authored andcommitted
[dart2js] new-rti: Simplification and branch-strengthening for 'is'
Change-Id: I49d712b303400fe2f2109b6c9f8fb684917df0ef Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112701 Reviewed-by: Mayank Patke <[email protected]> Commit-Queue: Stephen Adams <[email protected]>
1 parent f444374 commit bd47ec2

File tree

9 files changed

+214
-21
lines changed

9 files changed

+214
-21
lines changed

pkg/compiler/lib/src/inferrer/abstract_value_domain.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ abstract class AbstractValueDomain {
207207
/// reasoning, for example, that a dominating check uses the same type
208208
/// expression.
209209
AbstractValueWithPrecision createFromStaticType(DartType type,
210-
[ClassRelation classRelation = ClassRelation.subtype]);
210+
{ClassRelation classRelation = ClassRelation.subtype, bool nullable});
211211

212212
/// Creates an [AbstractValue] for a non-null exact instance of [cls].
213213
AbstractValue createNonNullExact(ClassEntity cls);

pkg/compiler/lib/src/inferrer/trivial.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,11 @@ class TrivialAbstractValueDomain implements AbstractValueDomain {
360360

361361
@override
362362
AbstractValueWithPrecision createFromStaticType(DartType type,
363-
[ClassRelation classRelation = ClassRelation.subtype]) =>
364-
const AbstractValueWithPrecision(const TrivialAbstractValue(), false);
363+
{ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
364+
assert(nullable != null);
365+
return const AbstractValueWithPrecision(
366+
const TrivialAbstractValue(), false);
367+
}
365368

366369
@override
367370
AbstractValue get asyncStarStreamType => const TrivialAbstractValue();

pkg/compiler/lib/src/inferrer/typemasks/masks.dart

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,13 @@ class CommonMasks implements AbstractValueDomain {
265265

266266
@override
267267
AbstractValueWithPrecision createFromStaticType(DartType type,
268-
[ClassRelation classRelation = ClassRelation.subtype]) {
268+
{ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
269+
assert(nullable != null);
270+
AbstractValueWithPrecision finish(TypeMask value, bool isPrecise) {
271+
return AbstractValueWithPrecision(
272+
nullable ? value : value.nonNullable(), isPrecise);
273+
}
274+
269275
bool isPrecise = true;
270276
while (type is TypeVariableType) {
271277
TypeVariableType typeVariable = type;
@@ -274,6 +280,7 @@ class CommonMasks implements AbstractValueDomain {
274280
classRelation = ClassRelation.subtype;
275281
isPrecise = false;
276282
}
283+
277284
if (type is InterfaceType) {
278285
if (isPrecise) {
279286
// TODO(sra): Could be precise if instantiated-to-bounds.
@@ -284,24 +291,22 @@ class CommonMasks implements AbstractValueDomain {
284291
}
285292
switch (classRelation) {
286293
case ClassRelation.exact:
287-
return AbstractValueWithPrecision(
288-
TypeMask.exact(type.element, _closedWorld), isPrecise);
294+
return finish(TypeMask.exact(type.element, _closedWorld), isPrecise);
289295
case ClassRelation.thisExpression:
290296
if (!_closedWorld.isUsedAsMixin(type.element)) {
291-
return AbstractValueWithPrecision(
297+
return finish(
292298
TypeMask.subclass(type.element, _closedWorld), isPrecise);
293299
}
294300
break;
295301
case ClassRelation.subtype:
296302
break;
297303
}
298-
return AbstractValueWithPrecision(
299-
TypeMask.subtype(type.element, _closedWorld), isPrecise);
304+
return finish(TypeMask.subtype(type.element, _closedWorld), isPrecise);
300305
} else if (type is FunctionType) {
301-
return AbstractValueWithPrecision(
306+
return finish(
302307
TypeMask.subtype(commonElements.functionClass, _closedWorld), false);
303308
} else {
304-
return AbstractValueWithPrecision(dynamicType, false);
309+
return finish(dynamicType, false);
305310
}
306311
}
307312

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4055,8 +4055,8 @@ class KernelSsaGraphBuilder extends ir.Visitor {
40554055
StaticType receiverStaticType =
40564056
_getStaticType(invocation.arguments.positional[1]);
40574057
AbstractValue receiverType = _abstractValueDomain
4058-
.createFromStaticType(
4059-
receiverStaticType.type, receiverStaticType.relation)
4058+
.createFromStaticType(receiverStaticType.type,
4059+
classRelation: receiverStaticType.relation, nullable: true)
40604060
.abstractValue;
40614061
push(new HInvokeClosure(selector, receiverType, inputs,
40624062
_abstractValueDomain.dynamicType, typeArguments));
@@ -4811,8 +4811,8 @@ class KernelSsaGraphBuilder extends ir.Visitor {
48114811
List<DartType> typeArguments,
48124812
SourceInformation sourceInformation) {
48134813
AbstractValue typeBound = _abstractValueDomain
4814-
.createFromStaticType(
4815-
staticReceiverType.type, staticReceiverType.relation)
4814+
.createFromStaticType(staticReceiverType.type,
4815+
classRelation: staticReceiverType.relation, nullable: true)
48164816
.abstractValue;
48174817
receiverType = receiverType == null
48184818
? typeBound
@@ -5404,7 +5404,11 @@ class KernelSsaGraphBuilder extends ir.Visitor {
54045404
if (options.experimentNewRti) {
54055405
HInstruction rti =
54065406
_typeBuilder.analyzeTypeArgumentNewRti(typeValue, sourceElement);
5407-
push(HIsTest(typeValue, expression, rti, _abstractValueDomain.boolType));
5407+
AbstractValueWithPrecision checkedType =
5408+
_abstractValueDomain.createFromStaticType(typeValue, nullable: false);
5409+
5410+
push(HIsTest(typeValue, checkedType, expression, rti,
5411+
_abstractValueDomain.boolType));
54085412
return;
54095413
}
54105414

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4352,10 +4352,11 @@ class HTypeInfoExpression extends HInstruction {
43524352
/// lowered to other instructions, so this instruction remains for types that
43534353
/// depend on type variables and complex types.
43544354
class HIsTest extends HInstruction {
4355+
final AbstractValueWithPrecision checkedAbstractValue;
43554356
final DartType dartType;
43564357

4357-
HIsTest(
4358-
this.dartType, HInstruction checked, HInstruction rti, AbstractValue type)
4358+
HIsTest(this.dartType, this.checkedAbstractValue, HInstruction checked,
4359+
HInstruction rti, AbstractValue type)
43594360
: super([rti, checked], type) {
43604361
setUseGvn();
43614362
}

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

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,9 @@ class SsaInstructionSimplifier extends HBaseVisitor
761761
_closedWorld.elementEnvironment.getFieldType(field);
762762
HInstruction closureCall = new HInvokeClosure(
763763
callSelector,
764-
_abstractValueDomain.createFromStaticType(fieldType).abstractValue,
764+
_abstractValueDomain
765+
.createFromStaticType(fieldType, nullable: true)
766+
.abstractValue,
765767
inputs,
766768
node.instructionType,
767769
node.typeArguments)
@@ -1877,7 +1879,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
18771879
dartType, node.isTypeError, _closedWorld.commonElements);
18781880
if (specializedCheck != null) {
18791881
AbstractValueWithPrecision checkedType =
1880-
_abstractValueDomain.createFromStaticType(dartType);
1882+
_abstractValueDomain.createFromStaticType(dartType, nullable: true);
18811883
return HAsCheckSimple(node.checkedInput, dartType, checkedType,
18821884
node.isTypeError, specializedCheck, node.instructionType);
18831885
}
@@ -1891,6 +1893,27 @@ class SsaInstructionSimplifier extends HBaseVisitor
18911893
return node;
18921894
}
18931895

1896+
@override
1897+
HInstruction visitIsTest(HIsTest node) {
1898+
AbstractValueWithPrecision checkedAbstractValue = node.checkedAbstractValue;
1899+
HInstruction checkedInput = node.checkedInput;
1900+
AbstractValue inputType = checkedInput.instructionType;
1901+
1902+
AbstractBool isIn = _abstractValueDomain.isIn(
1903+
inputType, checkedAbstractValue.abstractValue);
1904+
1905+
if (isIn.isDefinitelyFalse) {
1906+
return _graph.addConstantBool(false, _closedWorld);
1907+
}
1908+
if (!checkedAbstractValue.isPrecise) return node;
1909+
1910+
if (isIn.isDefinitelyTrue) {
1911+
return _graph.addConstantBool(true, _closedWorld);
1912+
}
1913+
1914+
return node;
1915+
}
1916+
18941917
@override
18951918
HInstruction visitInstanceEnvironment(HInstanceEnvironment node) {
18961919
HInstruction instance = node.inputs.single;
@@ -2954,6 +2977,27 @@ class SsaTypeConversionInserter extends HBaseVisitor
29542977
// false. Avoid strengthening to `null`.
29552978
}
29562979

2980+
@override
2981+
void visitIsTest(HIsTest instruction) {
2982+
List<HBasicBlock> trueTargets = <HBasicBlock>[];
2983+
List<HBasicBlock> falseTargets = <HBasicBlock>[];
2984+
2985+
collectTargets(instruction, trueTargets, falseTargets);
2986+
2987+
if (trueTargets.isEmpty && falseTargets.isEmpty) return;
2988+
2989+
AbstractValue convertedType =
2990+
instruction.checkedAbstractValue.abstractValue;
2991+
HInstruction input = instruction.checkedInput;
2992+
2993+
for (HBasicBlock block in trueTargets) {
2994+
insertTypePropagationForDominatedUsers(block, input, convertedType);
2995+
}
2996+
// TODO(sra): Also strengthen uses for when the condition is precise and
2997+
// known false (e.g. int? x; ... if (x is! int) use(x)). Avoid strengthening
2998+
// to `null`.
2999+
}
3000+
29573001
@override
29583002
void visitIdentity(HIdentity instruction) {
29593003
// At HIf(HIdentity(x, null)) strengthens x to non-null on else branch.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ abstract class TypeBuilder {
480480
type, builder.sourceElement,
481481
sourceInformation: sourceInformation);
482482
AbstractValueWithPrecision checkedType =
483-
_abstractValueDomain.createFromStaticType(type);
483+
_abstractValueDomain.createFromStaticType(type, nullable: true);
484484
AbstractValue instructionType = _abstractValueDomain.intersection(
485485
original.instructionType, checkedType.abstractValue);
486486
return HAsCheck(
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
library new_rti_is_test;
6+
7+
import 'dart:async';
8+
import 'package:async_helper/async_helper.dart';
9+
import '../helpers/compiler_helper.dart';
10+
11+
// 'N' tests all have a nullable input so should not reduce is-test.
12+
// TODO(NNBD): Add tests with non-nullable input types.
13+
14+
const TEST1N = r"""
15+
foo(int a) {
16+
return a is double;
17+
// absent: 'return true'
18+
// absent: 'return false'
19+
}
20+
""";
21+
22+
const TEST2N = r"""
23+
foo(int a) {
24+
return a is num;
25+
// absent: 'return true'
26+
// absent: 'return false'
27+
}
28+
""";
29+
30+
const TEST3N = r"""
31+
foo(double a) {
32+
return a is int;
33+
// absent: 'return true'
34+
// absent: 'return false'
35+
}
36+
""";
37+
38+
const TEST4N = r"""
39+
foo(double a) {
40+
return a is num;
41+
// absent: 'return true'
42+
// absent: 'return false'
43+
}
44+
""";
45+
46+
const TEST5N = r"""
47+
foo(num a) {
48+
return a is int;
49+
// absent: 'return true'
50+
// absent: 'return false'
51+
}
52+
""";
53+
54+
const TEST6N = r"""
55+
foo(num a) {
56+
return a is double;
57+
// absent: 'return true'
58+
// absent: 'return false'
59+
}
60+
""";
61+
62+
const TEST1I = r"""
63+
foo(a) {
64+
if (a is int) return a is double;
65+
// present: 'return true'
66+
}
67+
""";
68+
69+
const TEST2I = r"""
70+
foo(a) {
71+
if (a is int) return a is num;
72+
// present: 'return true'
73+
}
74+
""";
75+
76+
const TEST3I = r"""
77+
foo(a) {
78+
if (a is double) return a is int;
79+
// absent: 'return true'
80+
// absent: 'return false'
81+
}
82+
""";
83+
84+
const TEST4I = r"""
85+
foo(a) {
86+
if (a is double) return a is num;
87+
// present: 'return true'
88+
}
89+
""";
90+
91+
const TEST5I = r"""
92+
foo(a) {
93+
if (a is num) return a is int;
94+
// absent: 'return true'
95+
// absent: 'return false'
96+
}
97+
""";
98+
99+
const TEST6I = r"""
100+
foo(a) {
101+
if (a is num) return a is double;
102+
// present: 'return true'
103+
}
104+
""";
105+
106+
main() {
107+
runTests() async {
108+
Future check(String test) {
109+
return compile(test,
110+
entry: 'foo', check: checkerForAbsentPresent(test), newRti: true);
111+
}
112+
113+
await check(TEST1N);
114+
await check(TEST2N);
115+
await check(TEST3N);
116+
await check(TEST4N);
117+
await check(TEST5N);
118+
await check(TEST6N);
119+
120+
await check(TEST1I);
121+
await check(TEST2I);
122+
await check(TEST3I);
123+
await check(TEST4I);
124+
await check(TEST5I);
125+
await check(TEST6I);
126+
}
127+
128+
asyncTest(() async {
129+
print('--test from kernel------------------------------------------------');
130+
await runTests();
131+
});
132+
}

tests/compiler/dart2js/helpers/compiler_helper.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Future<String> compile(String code,
3737
bool trustJSInteropTypeAnnotations: false,
3838
bool disableTypeInference: true,
3939
bool omitImplicitChecks: true,
40+
bool newRti: false,
4041
void check(String generatedEntry),
4142
bool returnAll: false}) async {
4243
OutputCollector outputCollector = returnAll ? new OutputCollector() : null;
@@ -59,6 +60,9 @@ Future<String> compile(String code,
5960
if (disableInlining) {
6061
options.add(Flags.disableInlining);
6162
}
63+
if (newRti) {
64+
options.add(Flags.experimentNewRti);
65+
}
6266

6367
// Pretend this is a dart2js_native test to allow use of 'native' keyword
6468
// and import of private libraries.

0 commit comments

Comments
 (0)