[dart2js] Generate new-rti SSA instructions for checks
There is no codegen yet so almost all code compiled with
--experiment-new-rti will crash the compiler.
Change-Id: Idf542646ac3629cb02a50d44c2a98abd156047ed
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106001
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 3d8a473..c3bbed6 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -4373,7 +4373,8 @@
HAsCheck(HInstruction checked, HInstruction rti, this.isTypeError,
AbstractValue type)
- : super([rti, checked], type) {}
+ : assert(isTypeError != null),
+ super([rti, checked], type);
// The type input is first to facilitate the `type.as(value)` codegen pattern.
HInstruction get typeInput => inputs[0];
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 249121e..1a27e5b 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -1322,6 +1322,11 @@
// convention, but is not a call on an interceptor.
HInstruction value = node.inputs.last;
if (_options.parameterCheckPolicy.isEmitted) {
+ if (_options.experimentNewRti) {
+ // TODO(sra): Implement inlining of setters with checks for new rti.
+ node.needsCheck = true;
+ return node;
+ }
DartType type = _closedWorld.elementEnvironment.getFieldType(field);
if (!type.treatAsRaw ||
type.isTypeVariable ||
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index 95bfbb5..539261d 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -696,13 +696,13 @@
@override
visitLoadType(HLoadType node) {
var inputs = node.inputs.map(temporaryId).join(', ');
- return "LoadType: $inputs";
+ return "LoadType: ${node.typeExpression} $inputs";
}
@override
visitTypeEval(HTypeEval node) {
var inputs = node.inputs.map(temporaryId).join(', ');
- return "TypeEval: $inputs";
+ return "TypeEval: ${node.typeExpression} $inputs";
}
@override
diff --git a/pkg/compiler/lib/src/ssa/type_builder.dart b/pkg/compiler/lib/src/ssa/type_builder.dart
index 0a5d8fe..d546cfe 100644
--- a/pkg/compiler/lib/src/ssa/type_builder.dart
+++ b/pkg/compiler/lib/src/ssa/type_builder.dart
@@ -69,10 +69,11 @@
/// Produces code that checks the runtime type is actually the type specified
/// by attempting a type conversion.
- HInstruction _checkType(HInstruction original, DartType type, int kind) {
+ HInstruction _checkType(HInstruction original, DartType type) {
assert(type != null);
type = builder.localsHandler.substInContext(type);
- HInstruction other = buildTypeConversion(original, type, kind);
+ HInstruction other =
+ buildTypeConversion(original, type, HTypeConversion.TYPE_CHECK);
// TODO(johnniwinther): This operation on `registry` may be inconsistent.
// If it is needed then it seems likely that similar invocations of
// `buildTypeConversion` in `SsaBuilder.visitAs` should also be followed by
@@ -116,7 +117,7 @@
if (builder.options.parameterCheckPolicy.isTrusted) {
checkedOrTrusted = _trustType(original, type);
} else if (builder.options.parameterCheckPolicy.isEmitted) {
- checkedOrTrusted = _checkType(original, type, HTypeConversion.TYPE_CHECK);
+ checkedOrTrusted = _checkType(original, type);
}
if (checkedOrTrusted == original) return original;
builder.add(checkedOrTrusted);
@@ -127,14 +128,13 @@
/// instruction that checks the type is what we expect or automatically
/// trusts the written type.
HInstruction potentiallyCheckOrTrustTypeOfAssignment(
- HInstruction original, DartType type,
- {int kind: HTypeConversion.TYPE_CHECK}) {
+ HInstruction original, DartType type) {
if (type == null) return original;
HInstruction checkedOrTrusted = original;
if (builder.options.assignmentCheckPolicy.isTrusted) {
checkedOrTrusted = _trustType(original, type);
} else if (builder.options.assignmentCheckPolicy.isEmitted) {
- checkedOrTrusted = _checkType(original, type, kind);
+ checkedOrTrusted = _checkType(original, type);
}
if (checkedOrTrusted == original) return original;
builder.add(checkedOrTrusted);
@@ -273,6 +273,28 @@
return result;
}
+ HInstruction analyzeTypeArgumentNewRti(
+ DartType argument, MemberEntity sourceElement,
+ {SourceInformation sourceInformation}) {
+ argument = argument.unaliased;
+
+ if (argument.containsFreeTypeVariables) {
+ // TODO(sra): Locate type environment.
+ HInstruction environment =
+ builder.graph.addConstantString("env", _closedWorld);
+ HInstruction rti =
+ HTypeEval(environment, argument, _abstractValueDomain.dynamicType)
+ ..sourceInformation = sourceInformation;
+ builder.add(rti);
+ return rti;
+ }
+
+ HInstruction rti = HLoadType(argument, _abstractValueDomain.dynamicType)
+ ..sourceInformation = sourceInformation;
+ builder.add(rti);
+ return rti;
+ }
+
/// Build a [HTypeConversion] for converting [original] to type [type].
///
/// Invariant: [type] must be valid in the context.
@@ -280,6 +302,12 @@
HInstruction buildTypeConversion(
HInstruction original, DartType type, int kind,
{SourceInformation sourceInformation}) {
+ if (builder.options.experimentNewRti) {
+ return buildAsCheck(original, type,
+ isTypeError: kind == HTypeConversion.TYPE_CHECK,
+ sourceInformation: sourceInformation);
+ }
+
if (type == null) return original;
type = type.unaliased;
if (type.isInterfaceType && !type.treatAsRaw) {
@@ -312,4 +340,30 @@
..sourceInformation = sourceInformation;
}
}
+
+ /// Build a [HAsCheck] for converting [original] to type [type].
+ ///
+ /// Invariant: [type] must be valid in the context.
+ /// See [LocalsHandler.substInContext].
+ HInstruction buildAsCheck(HInstruction original, DartType type,
+ {bool isTypeError, SourceInformation sourceInformation}) {
+ if (type == null) return original;
+ type = type.unaliased;
+
+ HInstruction reifiedType =
+ analyzeTypeArgumentNewRti(type, builder.sourceElement);
+ if (type is InterfaceType) {
+ // TODO(sra): Under NNDB opt-in, this will be NonNullable.
+ AbstractValue subtype =
+ _abstractValueDomain.createNullableSubtype(type.element);
+ return HAsCheck(original, reifiedType, isTypeError, subtype)
+ ..sourceInformation = sourceInformation;
+ } else {
+ // TypeMasks don't encode function types or FutureOr types or type
+ // variable types.
+ AbstractValue abstractValue = original.instructionType;
+ return HAsCheck(original, reifiedType, isTypeError, abstractValue)
+ ..sourceInformation = sourceInformation;
+ }
+ }
}