New Rti SSA nodes
Change-Id: I1448239274803ca3e1dae4c602996662a11f2f1e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105408
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 1b97f87..5fabe81 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -3330,4 +3330,34 @@
void visitRef(HRef node) {
visit(node.value);
}
+
+ @override
+ visitIsTest(HIsTest node) {
+ throw UnimplementedError('SsaCodeGenerator.visitIsTest');
+ }
+
+ @override
+ visitAsCheck(HAsCheck node) {
+ throw UnimplementedError('SsaCodeGenerator.visitAsCheck');
+ }
+
+ @override
+ visitSubtypeCheck(HSubtypeCheck node) {
+ throw UnimplementedError('SsaCodeGenerator.visitSubtypeCheck');
+ }
+
+ @override
+ visitLoadType(HLoadType node) {
+ throw UnimplementedError('SsaCodeGenerator.visitLoadType');
+ }
+
+ @override
+ visitTypeEval(HTypeEval node) {
+ throw UnimplementedError('SsaCodeGenerator.visitTypeEval');
+ }
+
+ @override
+ visitTypeBind(HTypeBind node) {
+ throw UnimplementedError('SsaCodeGenerator.visitTypeBind');
+ }
}
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index db7f6f6..3d8a473 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -103,6 +103,14 @@
R visitTypeInfoReadRaw(HTypeInfoReadRaw node);
R visitTypeInfoReadVariable(HTypeInfoReadVariable node);
R visitTypeInfoExpression(HTypeInfoExpression node);
+
+ // Instructions for 'dart:_rti'.
+ R visitIsTest(HIsTest node);
+ R visitAsCheck(HAsCheck node);
+ R visitSubtypeCheck(HSubtypeCheck node);
+ R visitLoadType(HLoadType node);
+ R visitTypeEval(HTypeEval node);
+ R visitTypeBind(HTypeBind node);
}
abstract class HGraphVisitor {
@@ -584,8 +592,22 @@
@override
visitTypeInfoReadVariable(HTypeInfoReadVariable node) =>
visitInstruction(node);
+
@override
visitTypeInfoExpression(HTypeInfoExpression node) => visitInstruction(node);
+
+ @override
+ visitIsTest(HIsTest node) => visitInstruction(node);
+ @override
+ visitAsCheck(HAsCheck node) => visitCheck(node);
+ @override
+ visitSubtypeCheck(HSubtypeCheck node) => visitCheck(node);
+ @override
+ visitLoadType(HLoadType node) => visitInstruction(node);
+ @override
+ visitTypeEval(HTypeEval node) => visitInstruction(node);
+ @override
+ visitTypeBind(HTypeBind node) => visitInstruction(node);
}
class SubGraph {
@@ -1064,6 +1086,13 @@
static const int BOOL_CONVERSION_TYPECODE = 45;
static const int PRIMITIVE_CHECK_TYPECODE = 46;
+ static const int IS_TEST_TYPECODE = 47;
+ static const int AS_CHECK_TYPECODE = 48;
+ static const int SUBTYPE_CHECK_TYPECODE = 49;
+ static const int LOAD_TYPE_TYPECODE = 50;
+ static const int TYPE_EVAL_TYPECODE = 51;
+ static const int TYPE_BIND_TYPECODE = 52;
+
HInstruction(this.inputs, this.instructionType)
: id = idCounter++,
usedBy = <HInstruction>[] {
@@ -1384,6 +1413,9 @@
bool hasSameLoopHeaderAs(HInstruction other) {
return block.enclosingLoopHeader == other.block.enclosingLoopHeader;
}
+
+ @override
+ String toString() => '${this.runtimeType}()';
}
/// The set of uses of [source] that are dominated by [dominator].
@@ -3342,6 +3374,7 @@
receiver.isNull(domain).isPotentiallyTrue;
}
+/// Is-test using legacy constructor based typ representation.
class HIs extends HInstruction {
/// A check against a raw type: 'o is int', 'o is A'.
static const int RAW_CHECK = 0;
@@ -3476,7 +3509,7 @@
///
/// HLateValue is useful for naming values that would otherwise be generated at
/// use site, for example, if 'this' is used many times, replacing uses of
-/// 'this' with HLateValhe(HThis) will have the effect of copying 'this' to a
+/// 'this' with HLateValue(HThis) will have the effect of copying 'this' to a
/// temporary will reduce the size of minified code.
class HLateValue extends HLateInstruction {
HLateValue(HInstruction target) : super([target], target.instructionType);
@@ -3489,6 +3522,7 @@
toString() => 'HLateValue($target)';
}
+/// Type check or cast using legacy constructor-based type representation.
class HTypeConversion extends HCheck {
// Values for [kind].
static const int TYPE_CHECK = 0;
@@ -4299,3 +4333,179 @@
}
}
}
+
+// -----------------------------------------------------------------------------
+
+/// Is-test using Rti form of type expression.
+///
+/// This instruction can be used for any type. Tests for simple types are
+/// lowered to other instructions, so this instruction remains for types that
+/// depend on type variables and complex types.
+class HIsTest extends HInstruction {
+ HIsTest(HInstruction checked, HInstruction rti, AbstractValue type)
+ : super([rti, checked], type) {
+ setUseGvn();
+ }
+
+ // The type input is first to facilitate the `type.is(value)` codegen pattern.
+ HInstruction get typeInput => inputs[0];
+ HInstruction get checkedInput => inputs[1];
+
+ @override
+ accept(HVisitor visitor) => visitor.visitIsTest(this);
+
+ @override
+ int typeCode() => HInstruction.IS_TEST_TYPECODE;
+
+ @override
+ bool typeEquals(HInstruction other) => other is HIsTest;
+
+ @override
+ bool dataEquals(HIsTest other) => true;
+
+ @override
+ String toString() => 'HIsTest()';
+}
+
+/// Type cast or type check using Rti form of type expression.
+class HAsCheck extends HCheck {
+ final bool isTypeError;
+
+ HAsCheck(HInstruction checked, HInstruction rti, this.isTypeError,
+ AbstractValue type)
+ : super([rti, checked], type) {}
+
+ // The type input is first to facilitate the `type.as(value)` codegen pattern.
+ HInstruction get typeInput => inputs[0];
+ @override
+ HInstruction get checkedInput => inputs[1];
+
+ @override
+ accept(HVisitor visitor) => visitor.visitAsCheck(this);
+
+ @override
+ int typeCode() => HInstruction.AS_CHECK_TYPECODE;
+
+ @override
+ bool typeEquals(HInstruction other) => other is HAsCheck;
+
+ @override
+ bool dataEquals(HAsCheck other) {
+ return isTypeError == other.isTypeError;
+ }
+
+ @override
+ String toString() {
+ String error = isTypeError ? 'TypeError' : 'CastError';
+ return 'HAsCheck($error)';
+ }
+}
+
+/// Subtype check comparing two Rti types.
+class HSubtypeCheck extends HCheck {
+ HSubtypeCheck(
+ HInstruction subtype, HInstruction supertype, AbstractValue type)
+ : super([subtype, supertype], type) {
+ setUseGvn();
+ }
+
+ HInstruction get typeInput => inputs[1];
+
+ @override
+ accept(HVisitor visitor) => visitor.visitSubtypeCheck(this);
+
+ @override
+ int typeCode() => HInstruction.SUBTYPE_CHECK_TYPECODE;
+
+ @override
+ bool typeEquals(HInstruction other) => other is HSubtypeCheck;
+
+ @override
+ bool dataEquals(HSubtypeCheck other) => true;
+
+ @override
+ String toString() => 'HSubtypeCheck()';
+}
+
+/// Common superclass for instructions that generate Rti values.
+abstract class HRtiInstruction extends HInstruction {
+ HRtiInstruction(List<HInstruction> inputs, AbstractValue type)
+ : super(inputs, type);
+}
+
+/// Evaluates an Rti type recipe in the global environment.
+class HLoadType extends HRtiInstruction {
+ DartType typeExpression; // TODO(sra): Allow a type environment expression.
+
+ HLoadType(this.typeExpression, AbstractValue type) : super([], type) {
+ setUseGvn();
+ }
+
+ @override
+ accept(HVisitor visitor) => visitor.visitLoadType(this);
+
+ @override
+ int typeCode() => HInstruction.LOAD_TYPE_TYPECODE;
+
+ @override
+ bool typeEquals(HInstruction other) => other is HLoadType;
+
+ @override
+ bool dataEquals(HLoadType other) {
+ return typeExpression == other.typeExpression;
+ }
+
+ @override
+ String toString() => 'HLoadType($typeExpression)';
+}
+
+/// Evaluates an Rti type recipe in an Rti environment.
+class HTypeEval extends HRtiInstruction {
+ DartType typeExpression; // TODO(sra); Allow a type environment expression.
+
+ HTypeEval(HInstruction environment, this.typeExpression, AbstractValue type)
+ : super([environment], type) {
+ setUseGvn();
+ }
+
+ @override
+ accept(HVisitor visitor) => visitor.visitTypeEval(this);
+
+ @override
+ int typeCode() => HInstruction.TYPE_EVAL_TYPECODE;
+
+ @override
+ bool typeEquals(HInstruction other) => other is HTypeEval;
+
+ @override
+ bool dataEquals(HTypeEval other) {
+ return typeExpression == other.typeExpression;
+ }
+
+ @override
+ String toString() => 'HTypeEval($typeExpression)';
+}
+
+/// Extends an Rti type environment with generic function types.
+class HTypeBind extends HRtiInstruction {
+ HTypeBind(
+ HInstruction environment, HInstruction typeArguments, AbstractValue type)
+ : super([environment, typeArguments], type) {
+ setUseGvn();
+ }
+
+ @override
+ accept(HVisitor visitor) => visitor.visitTypeBind(this);
+
+ @override
+ int typeCode() => HInstruction.TYPE_BIND_TYPECODE;
+
+ @override
+ bool typeEquals(HInstruction other) => other is HTypeBind;
+
+ @override
+ bool dataEquals(HTypeBind other) => true;
+
+ @override
+ String toString() => 'HTypeBind()';
+}
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index db7b380..95bfbb5 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -673,4 +673,41 @@
String visitYield(HYield node) {
return "Yield${node.hasStar ? "*" : ""}: ${temporaryId(node.inputs[0])}";
}
+
+ @override
+ visitIsTest(HIsTest node) {
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "IsTest: $inputs";
+ }
+
+ @override
+ visitAsCheck(HAsCheck node) {
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ String error = node.isTypeError ? 'TypeError' : 'CastError';
+ return "AsCheck: $error $inputs";
+ }
+
+ @override
+ visitSubtypeCheck(HSubtypeCheck node) {
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "SubtypeCheck: $inputs";
+ }
+
+ @override
+ visitLoadType(HLoadType node) {
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "LoadType: $inputs";
+ }
+
+ @override
+ visitTypeEval(HTypeEval node) {
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "TypeEval: $inputs";
+ }
+
+ @override
+ visitTypeBind(HTypeBind node) {
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "TypeBind: $inputs";
+ }
}