Skip to content

Commit 6d13a6d

Browse files
rakudramacommit-bot@chromium.org
authored andcommitted
[dart2js] new-rti: Lower some checks to a simpler form
HAsCheckSimple is a specialization of HAsCheck that calls a js_runtime helper to do the check. This CL specializes bool/double/int/num/String. is-checks are not included but used by as/type checks, so there is not much speedup for this CL. Change-Id: Id65941d789e017350d3f9e181174e4cce768eea5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/110422 Commit-Queue: Stephen Adams <[email protected]> Reviewed-by: Mayank Patke <[email protected]>
1 parent ed2764d commit 6d13a6d

File tree

10 files changed

+414
-22
lines changed

10 files changed

+414
-22
lines changed

pkg/compiler/lib/src/common_elements.dart

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,21 @@ abstract class CommonElements {
496496
FunctionEntity get generalAsCheckImplementation;
497497
FunctionEntity get generalTypeCheckImplementation;
498498

499+
FunctionEntity get specializedIsBool;
500+
FunctionEntity get specializedAsBoolNullable;
501+
FunctionEntity get specializedCheckBoolNullable;
502+
FunctionEntity get specializedAsDoubleNullable;
503+
FunctionEntity get specializedCheckDoubleNullable;
504+
FunctionEntity get specializedIsInt;
505+
FunctionEntity get specializedAsIntNullable;
506+
FunctionEntity get specializedCheckIntNullable;
507+
FunctionEntity get specializedIsNum;
508+
FunctionEntity get specializedAsNumNullable;
509+
FunctionEntity get specializedCheckNumNullable;
510+
FunctionEntity get specializedIsString;
511+
FunctionEntity get specializedAsStringNullable;
512+
FunctionEntity get specializedCheckStringNullable;
513+
499514
// From dart:_internal
500515

501516
ClassEntity get symbolImplementationClass;
@@ -1892,6 +1907,58 @@ class CommonElementsImpl
18921907
_generalTypeCheckImplementation ??=
18931908
_findRtiFunction('_generalTypeCheckImplementation');
18941909

1910+
@override
1911+
FunctionEntity get specializedIsBool => _findRtiFunction('_isBool');
1912+
1913+
@override
1914+
FunctionEntity get specializedAsBoolNullable =>
1915+
_findRtiFunction('_asBoolNullable');
1916+
1917+
@override
1918+
FunctionEntity get specializedCheckBoolNullable =>
1919+
_findRtiFunction('_checkBoolNullable');
1920+
1921+
@override
1922+
FunctionEntity get specializedAsDoubleNullable =>
1923+
_findRtiFunction('_asDoubleNullable');
1924+
1925+
@override
1926+
FunctionEntity get specializedCheckDoubleNullable =>
1927+
_findRtiFunction('_checkDoubleNullable');
1928+
1929+
@override
1930+
FunctionEntity get specializedIsInt => _findRtiFunction('_isInt');
1931+
1932+
@override
1933+
FunctionEntity get specializedAsIntNullable =>
1934+
_findRtiFunction('_asIntNullable');
1935+
1936+
@override
1937+
FunctionEntity get specializedCheckIntNullable =>
1938+
_findRtiFunction('_checkIntNullable');
1939+
1940+
@override
1941+
FunctionEntity get specializedIsNum => _findRtiFunction('_isNum');
1942+
1943+
@override
1944+
FunctionEntity get specializedAsNumNullable =>
1945+
_findRtiFunction('_asNumNullable');
1946+
1947+
@override
1948+
FunctionEntity get specializedCheckNumNullable =>
1949+
_findRtiFunction('_checkNumNullable');
1950+
1951+
@override
1952+
FunctionEntity get specializedIsString => _findRtiFunction('_isString');
1953+
1954+
@override
1955+
FunctionEntity get specializedAsStringNullable =>
1956+
_findRtiFunction('_asStringNullable');
1957+
1958+
@override
1959+
FunctionEntity get specializedCheckStringNullable =>
1960+
_findRtiFunction('_checkStringNullable');
1961+
18951962
// From dart:_internal
18961963

18971964
ClassEntity _symbolImplementationClass;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ class AbstractValueWithPrecision {
7171
final bool isPrecise;
7272

7373
const AbstractValueWithPrecision(this.abstractValue, this.isPrecise);
74+
75+
@override
76+
String toString() =>
77+
'AbstractValueWithPrecision($abstractValue, isPrecise: $isPrecise)';
7478
}
7579

7680
/// A system that implements an abstraction over runtime values.

pkg/compiler/lib/src/js_backend/backend_impact.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,22 @@ class BackendImpacts {
779779
_commonElements.generalIsTestImplementation,
780780
_commonElements.generalAsCheckImplementation,
781781
_commonElements.generalTypeCheckImplementation,
782+
// Specialized checks.
783+
_commonElements.specializedIsBool,
784+
_commonElements.specializedAsBoolNullable,
785+
_commonElements.specializedCheckBoolNullable,
786+
// no specializedIsDouble.
787+
_commonElements.specializedAsDoubleNullable,
788+
_commonElements.specializedCheckDoubleNullable,
789+
_commonElements.specializedIsInt,
790+
_commonElements.specializedAsIntNullable,
791+
_commonElements.specializedCheckIntNullable,
792+
_commonElements.specializedIsNum,
793+
_commonElements.specializedAsNumNullable,
794+
_commonElements.specializedCheckNumNullable,
795+
_commonElements.specializedIsString,
796+
_commonElements.specializedAsStringNullable,
797+
_commonElements.specializedCheckStringNullable,
782798
], globalUses: [])
783799
];
784800
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
import '../common_elements.dart' show JCommonElements;
6+
import '../elements/entities.dart';
7+
import '../elements/types.dart';
8+
9+
class SpecializedChecks {
10+
static MemberEntity findAsCheck(
11+
DartType dartType, bool isTypeError, JCommonElements commonElements) {
12+
if (dartType is InterfaceType) {
13+
if (dartType.typeArguments.isNotEmpty) return null;
14+
return _findAsCheck(dartType.element, commonElements,
15+
isTypeError: isTypeError, isNullable: true);
16+
}
17+
return null;
18+
}
19+
20+
static MemberEntity _findAsCheck(
21+
ClassEntity element, JCommonElements commonElements,
22+
{bool isTypeError, bool isNullable}) {
23+
if (element == commonElements.jsStringClass ||
24+
element == commonElements.stringClass) {
25+
if (isNullable) {
26+
return isTypeError
27+
? commonElements.specializedCheckStringNullable
28+
: commonElements.specializedAsStringNullable;
29+
}
30+
return null;
31+
}
32+
33+
if (element == commonElements.jsBoolClass ||
34+
element == commonElements.boolClass) {
35+
if (isNullable) {
36+
return isTypeError
37+
? commonElements.specializedCheckBoolNullable
38+
: commonElements.specializedAsBoolNullable;
39+
}
40+
return null;
41+
}
42+
43+
if (element == commonElements.jsDoubleClass ||
44+
element == commonElements.doubleClass) {
45+
if (isNullable) {
46+
return isTypeError
47+
? commonElements.specializedCheckDoubleNullable
48+
: commonElements.specializedAsDoubleNullable;
49+
}
50+
return null;
51+
}
52+
53+
if (element == commonElements.jsNumberClass ||
54+
element == commonElements.numClass) {
55+
if (isNullable) {
56+
return isTypeError
57+
? commonElements.specializedCheckNumNullable
58+
: commonElements.specializedAsNumNullable;
59+
}
60+
return null;
61+
}
62+
63+
if (element == commonElements.jsIntClass ||
64+
element == commonElements.intClass ||
65+
element == commonElements.jsUInt32Class ||
66+
element == commonElements.jsUInt31Class ||
67+
element == commonElements.jsPositiveIntClass) {
68+
if (isNullable) {
69+
return isTypeError
70+
? commonElements.specializedCheckIntNullable
71+
: commonElements.specializedAsIntNullable;
72+
}
73+
return null;
74+
}
75+
76+
return null;
77+
}
78+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
704704
if (instruction is HTypeConversion ||
705705
instruction is HPrimitiveCheck ||
706706
instruction is HAsCheck ||
707+
instruction is HAsCheckSimple ||
707708
instruction is HBoolConversion) {
708709
String inputName = variableNames.getName(instruction.checkedInput);
709710
if (variableNames.getName(instruction) == inputName) {
@@ -3373,6 +3374,17 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
33733374
node.sourceInformation));
33743375
}
33753376

3377+
@override
3378+
visitAsCheckSimple(HAsCheckSimple node) {
3379+
use(node.checkedInput);
3380+
MemberEntity method = node.method;
3381+
_registry.registerStaticUse(
3382+
StaticUse.staticInvoke(method, CallStructure.ONE_ARG));
3383+
js.Expression methodAccess = _emitter.staticFunctionAccess(method);
3384+
push(js.js(r'#(#)', [methodAccess, pop()]).withSourceInformation(
3385+
node.sourceInformation));
3386+
}
3387+
33763388
@override
33773389
visitSubtypeCheck(HSubtypeCheck node) {
33783390
throw UnimplementedError('SsaCodeGenerator.visitSubtypeCheck $node');

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,13 @@ class SsaInstructionMerger extends HBaseVisitor with CodegenPhase {
770770
visitInstruction(instruction);
771771
}
772772

773+
@override
774+
void visitAsCheckSimple(HAsCheckSimple instruction) {
775+
// Type checks and cast checks compile to code that only use their input
776+
// once, so we can safely visit them and try to merge the input.
777+
visitInstruction(instruction);
778+
}
779+
773780
@override
774781
void visitTypeEval(HTypeEval instruction) {
775782
// Type expressions compile to code that only use their input once, so we

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

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ abstract class HVisitor<R> {
108108
// Instructions for 'dart:_rti'.
109109
R visitIsTest(HIsTest node);
110110
R visitAsCheck(HAsCheck node);
111+
R visitAsCheckSimple(HAsCheckSimple node);
111112
R visitSubtypeCheck(HSubtypeCheck node);
112113
R visitLoadType(HLoadType node);
113114
R visitInstanceEnvironment(HInstanceEnvironment node);
@@ -603,6 +604,8 @@ class HBaseVisitor extends HGraphVisitor implements HVisitor {
603604
@override
604605
visitAsCheck(HAsCheck node) => visitCheck(node);
605606
@override
607+
visitAsCheckSimple(HAsCheckSimple node) => visitCheck(node);
608+
@override
606609
visitSubtypeCheck(HSubtypeCheck node) => visitCheck(node);
607610
@override
608611
visitLoadType(HLoadType node) => visitInstruction(node);
@@ -1092,11 +1095,12 @@ abstract class HInstruction implements Spannable {
10921095

10931096
static const int IS_TEST_TYPECODE = 47;
10941097
static const int AS_CHECK_TYPECODE = 48;
1095-
static const int SUBTYPE_CHECK_TYPECODE = 49;
1096-
static const int LOAD_TYPE_TYPECODE = 50;
1097-
static const int INSTANCE_ENVIRONMENT_TYPECODE = 51;
1098-
static const int TYPE_EVAL_TYPECODE = 52;
1099-
static const int TYPE_BIND_TYPECODE = 53;
1098+
static const int AS_CHECK_SIMPLE_TYPECODE = 49;
1099+
static const int SUBTYPE_CHECK_TYPECODE = 50;
1100+
static const int LOAD_TYPE_TYPECODE = 51;
1101+
static const int INSTANCE_ENVIRONMENT_TYPECODE = 52;
1102+
static const int TYPE_EVAL_TYPECODE = 53;
1103+
static const int TYPE_BIND_TYPECODE = 54;
11001104

11011105
HInstruction(this.inputs, this.instructionType)
11021106
: id = idCounter++,
@@ -4430,6 +4434,55 @@ class HAsCheck extends HCheck {
44304434
}
44314435
}
44324436

4437+
/// Type cast or type check for simple known types that are achieved via a
4438+
/// simple static call.
4439+
class HAsCheckSimple extends HCheck {
4440+
final DartType dartType;
4441+
final AbstractValueWithPrecision checkedType;
4442+
final bool isTypeError;
4443+
final MemberEntity method;
4444+
4445+
HAsCheckSimple(HInstruction checked, this.dartType, this.checkedType,
4446+
this.isTypeError, this.method, AbstractValue type)
4447+
: assert(isTypeError != null),
4448+
super([checked], type);
4449+
4450+
@override
4451+
HInstruction get checkedInput => inputs[0];
4452+
4453+
@override
4454+
bool isJsStatement() => false;
4455+
4456+
@override
4457+
accept(HVisitor visitor) => visitor.visitAsCheckSimple(this);
4458+
4459+
bool isRedundant(JClosedWorld closedWorld) {
4460+
if (!checkedType.isPrecise) return false;
4461+
AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
4462+
AbstractValue inputType = checkedInput.instructionType;
4463+
return abstractValueDomain
4464+
.isIn(inputType, checkedType.abstractValue)
4465+
.isDefinitelyTrue;
4466+
}
4467+
4468+
@override
4469+
int typeCode() => HInstruction.AS_CHECK_SIMPLE_TYPECODE;
4470+
4471+
@override
4472+
bool typeEquals(HInstruction other) => other is HAsCheckSimple;
4473+
4474+
@override
4475+
bool dataEquals(HAsCheckSimple other) {
4476+
return isTypeError == other.isTypeError && dartType == other.dartType;
4477+
}
4478+
4479+
@override
4480+
String toString() {
4481+
String error = isTypeError ? 'TypeError' : 'CastError';
4482+
return 'HAsCheck($error)';
4483+
}
4484+
}
4485+
44334486
/// Subtype check comparing two Rti types.
44344487
class HSubtypeCheck extends HCheck {
44354488
HSubtypeCheck(

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import '../js_backend/backend.dart' show CodegenInputs;
1919
import '../js_backend/native_data.dart' show NativeData;
2020
import '../js_backend/runtime_types_codegen.dart';
2121
import '../js_model/type_recipe.dart' show TypeRecipe;
22+
import '../js_backend/specialized_checks.dart';
2223
import '../native/behavior.dart';
2324
import '../options.dart';
2425
import '../universe/selector.dart' show Selector;
@@ -1859,6 +1860,26 @@ class SsaInstructionSimplifier extends HBaseVisitor
18591860
@override
18601861
HInstruction visitAsCheck(HAsCheck node) {
18611862
if (node.isRedundant(_closedWorld)) return node.checkedInput;
1863+
1864+
// See if this check can be lowered to a simple one.
1865+
HInstruction typeInput = node.typeInput;
1866+
if (typeInput is HLoadType) {
1867+
DartType dartType = typeInput.typeExpression;
1868+
MemberEntity specializedCheck = SpecializedChecks.findAsCheck(
1869+
dartType, node.isTypeError, _closedWorld.commonElements);
1870+
if (specializedCheck != null) {
1871+
AbstractValueWithPrecision checkedType =
1872+
_abstractValueDomain.createFromStaticType(dartType);
1873+
return HAsCheckSimple(node.checkedInput, dartType, checkedType,
1874+
node.isTypeError, specializedCheck, node.instructionType);
1875+
}
1876+
}
1877+
return node;
1878+
}
1879+
1880+
@override
1881+
HInstruction visitAsCheckSimple(HAsCheckSimple node) {
1882+
if (node.isRedundant(_closedWorld)) return node.checkedInput;
18621883
return node;
18631884
}
18641885
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,13 @@ class HInstructionStringifier implements HVisitor<String> {
687687
return "AsCheck: $error $inputs";
688688
}
689689

690+
@override
691+
String visitAsCheckSimple(HAsCheckSimple node) {
692+
var inputs = node.inputs.map(temporaryId).join(', ');
693+
String error = node.isTypeError ? 'TypeError' : 'CastError';
694+
return "AsCheckSimple: $error ${node.dartType} $inputs";
695+
}
696+
690697
@override
691698
String visitSubtypeCheck(HSubtypeCheck node) {
692699
var inputs = node.inputs.map(temporaryId).join(', ');

0 commit comments

Comments
 (0)