[vm/aot/tfa] Infer int type, devirtualize dynamic calls
This change improves type flow analysis to infer int types, in addition
to concrete classes (int type is abstract and has 2 concrete subclasses,
_Smi and _Mint).
Also, this CL enables devirtualization of dynamic calls (previously, only
calls with known interface target were devirtualized).
DartMicroBench.PrimeNumber:
x64: +221%
armv8: +461%
armv7h: +47.98%
No measurable impact on Flutter gallery build time in release mode.
Issue: https://github.com/flutter/flutter/issues/19677
Change-Id: I34db195f52f2a434218ee11eee7f308d4661738b
Reviewed-on: https://dart-review.googlesource.com/69520
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/pkg/vm/lib/metadata/inferred_type.dart b/pkg/vm/lib/metadata/inferred_type.dart
index 17daf11..91200ea 100644
--- a/pkg/vm/lib/metadata/inferred_type.dart
+++ b/pkg/vm/lib/metadata/inferred_type.dart
@@ -9,18 +9,25 @@
/// Metadata for annotating nodes with an inferred type information.
class InferredType {
final Reference _concreteClassReference;
- final bool nullable;
+ final int _flags;
- InferredType(Class concreteClass, bool nullable)
- : this._byReference(getClassReference(concreteClass), nullable);
+ static const int flagNullable = 1 << 0;
+ static const int flagInt = 1 << 1;
- InferredType._byReference(this._concreteClassReference, this.nullable);
+ InferredType(Class concreteClass, bool nullable, bool isInt)
+ : this._byReference(getClassReference(concreteClass),
+ (nullable ? flagNullable : 0) | (isInt ? flagInt : 0));
+
+ InferredType._byReference(this._concreteClassReference, this._flags);
Class get concreteClass => _concreteClassReference?.asClass;
+ bool get nullable => (_flags & flagNullable) != 0;
+ bool get isInt => (_flags & flagInt) != 0;
+
@override
String toString() =>
- "${concreteClass != null ? concreteClass : '!'}${nullable ? '?' : ''}";
+ "${concreteClass != null ? concreteClass : (isInt ? 'int' : '!')}${nullable ? '?' : ''}";
}
/// Repository for [InferredType].
@@ -35,14 +42,14 @@
void writeToBinary(InferredType metadata, Node node, BinarySink sink) {
sink.writeCanonicalNameReference(
getCanonicalNameOfClass(metadata.concreteClass));
- sink.writeByte(metadata.nullable ? 1 : 0);
+ sink.writeByte(metadata._flags);
}
@override
InferredType readFromBinary(Node node, BinarySource source) {
final concreteClassReference =
source.readCanonicalNameReference()?.getReference();
- final nullable = (source.readByte() != 0);
- return new InferredType._byReference(concreteClassReference, nullable);
+ final flags = source.readByte();
+ return new InferredType._byReference(concreteClassReference, flags);
}
}
diff --git a/pkg/vm/lib/transformations/devirtualization.dart b/pkg/vm/lib/transformations/devirtualization.dart
index b83c1cf..13c4908 100644
--- a/pkg/vm/lib/transformations/devirtualization.dart
+++ b/pkg/vm/lib/transformations/devirtualization.dart
@@ -72,7 +72,7 @@
directCall.checkReceiverForNull &&
_objectMemberNames.contains(directCall.target.name);
- DirectCallMetadata getDirectCall(TreeNode node, Member target,
+ DirectCallMetadata getDirectCall(TreeNode node, Member interfaceTarget,
{bool setter = false});
makeDirectCall(TreeNode node, Member target, DirectCallMetadata directCall) {
@@ -96,17 +96,20 @@
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
- Member target = node.interfaceTarget;
- if ((target != null) && isMethod(target)) {
- DirectCallMetadata directCall = getDirectCall(node, target);
- // TODO(dartbug.com/30480): Convert _isLegalTargetForMethodInvocation()
- // check into an assertion once front-end implements override checks.
- if ((directCall != null) &&
- isMethod(directCall.target) &&
- isLegalTargetForMethodInvocation(directCall.target, node.arguments) &&
- !hasExtraTargetForNull(directCall)) {
- makeDirectCall(node, target, directCall);
- }
+ final Member target = node.interfaceTarget;
+ if (target != null && !isMethod(target)) {
+ return;
+ }
+
+ final DirectCallMetadata directCall = getDirectCall(node, target);
+
+ // TODO(alexmarkov): Convert _isLegalTargetForMethodInvocation()
+ // check into an assertion once front-end implements all override checks.
+ if ((directCall != null) &&
+ isMethod(directCall.target) &&
+ isLegalTargetForMethodInvocation(directCall.target, node.arguments) &&
+ !hasExtraTargetForNull(directCall)) {
+ makeDirectCall(node, target, directCall);
}
}
@@ -114,14 +117,17 @@
visitPropertyGet(PropertyGet node) {
super.visitPropertyGet(node);
- Member target = node.interfaceTarget;
- if ((target != null) && isFieldOrGetter(target)) {
- DirectCallMetadata directCall = getDirectCall(node, target);
- if ((directCall != null) &&
- isFieldOrGetter(directCall.target) &&
- !hasExtraTargetForNull(directCall)) {
- makeDirectCall(node, target, directCall);
- }
+ final Member target = node.interfaceTarget;
+ if (target != null && !isFieldOrGetter(target)) {
+ return;
+ }
+
+ final DirectCallMetadata directCall = getDirectCall(node, target);
+
+ if ((directCall != null) &&
+ isFieldOrGetter(directCall.target) &&
+ !hasExtraTargetForNull(directCall)) {
+ makeDirectCall(node, target, directCall);
}
}
@@ -129,12 +135,11 @@
visitPropertySet(PropertySet node) {
super.visitPropertySet(node);
- Member target = node.interfaceTarget;
- if (target != null) {
- DirectCallMetadata directCall = getDirectCall(node, target, setter: true);
- if (directCall != null) {
- makeDirectCall(node, target, directCall);
- }
+ final Member target = node.interfaceTarget;
+ final DirectCallMetadata directCall =
+ getDirectCall(node, target, setter: true);
+ if (directCall != null) {
+ makeDirectCall(node, target, directCall);
}
}
}
@@ -148,10 +153,13 @@
: super(coreTypes, component, hierarchy);
@override
- DirectCallMetadata getDirectCall(TreeNode node, Member target,
+ DirectCallMetadata getDirectCall(TreeNode node, Member interfaceTarget,
{bool setter = false}) {
+ if (interfaceTarget == null) {
+ return null;
+ }
Member singleTarget = _hierarchySubtype
- .getSingleTargetForInterfaceInvocation(target, setter: setter);
+ .getSingleTargetForInterfaceInvocation(interfaceTarget, setter: setter);
if (singleTarget == null) {
return null;
}
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 82210b7..3ba77a7 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -450,6 +450,13 @@
}
_getReceiverTypeBuilder(targets, kNoSuchMethodMarker)
.addConcreteType(receiver);
+ } else if (selector is DynamicSelector) {
+ if (kPrintTrace) {
+ tracePrint(
+ "Dynamic selector - adding noSuchMethod for receiver $receiver");
+ }
+ _getReceiverTypeBuilder(targets, kNoSuchMethodMarker)
+ .addConcreteType(receiver);
} else {
if (kPrintTrace) {
tracePrint("Target is not found for receiver $receiver");
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index b17d1ad..0ed585c 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -1067,16 +1067,17 @@
}
@override
- visitSwitchStatement(SwitchStatement node) {
+ TypeExpr visitSwitchStatement(SwitchStatement node) {
_visit(node.expression);
for (var switchCase in node.cases) {
switchCase.expressions.forEach(_visit);
_visit(switchCase.body);
}
+ return null;
}
@override
- visitTryCatch(TryCatch node) {
+ TypeExpr visitTryCatch(TryCatch node) {
_visit(node.body);
for (var catchClause in node.catches) {
if (catchClause.exception != null) {
@@ -1087,49 +1088,56 @@
}
_visit(catchClause.body);
}
+ return null;
}
@override
- visitTryFinally(TryFinally node) {
+ TypeExpr visitTryFinally(TryFinally node) {
_visit(node.body);
_visit(node.finalizer);
+ return null;
}
@override
- visitVariableDeclaration(VariableDeclaration node) {
+ TypeExpr visitVariableDeclaration(VariableDeclaration node) {
final v = _declareVariable(node, addInitType: true);
if (node.initializer == null) {
v.values.add(_nullType);
}
+ return null;
}
@override
- visitWhileStatement(WhileStatement node) {
+ TypeExpr visitWhileStatement(WhileStatement node) {
_addUse(_visit(node.condition));
_visit(node.body);
+ return null;
}
@override
- visitYieldStatement(YieldStatement node) {
+ TypeExpr visitYieldStatement(YieldStatement node) {
_visit(node.expression);
+ return null;
}
@override
- visitFieldInitializer(FieldInitializer node) {
+ TypeExpr visitFieldInitializer(FieldInitializer node) {
final value = _visit(node.value);
final args = new Args<TypeExpr>([_receiver, value]);
_makeCall(node,
new DirectSelector(node.field, callKind: CallKind.PropertySet), args);
+ return null;
}
@override
- visitRedirectingInitializer(RedirectingInitializer node) {
+ TypeExpr visitRedirectingInitializer(RedirectingInitializer node) {
final args = _visitArguments(_receiver, node.arguments);
_makeCall(node, new DirectSelector(node.target), args);
+ return null;
}
@override
- visitSuperInitializer(SuperInitializer node) {
+ TypeExpr visitSuperInitializer(SuperInitializer node) {
final args = _visitArguments(_receiver, node.arguments);
Constructor target = null;
@@ -1146,22 +1154,27 @@
}
assertx(target != null);
_makeCall(node, new DirectSelector(target), args);
+ return null;
}
@override
- visitLocalInitializer(LocalInitializer node) {
+ TypeExpr visitLocalInitializer(LocalInitializer node) {
visitVariableDeclaration(node.variable);
+ return null;
}
@override
- visitAssertInitializer(AssertInitializer node) {
+ TypeExpr visitAssertInitializer(AssertInitializer node) {
if (!kRemoveAsserts) {
_visit(node.statement);
}
+ return null;
}
@override
- visitInvalidInitializer(InvalidInitializer node) {}
+ TypeExpr visitInvalidInitializer(InvalidInitializer node) {
+ return null;
+ }
@override
TypeExpr visitConstantExpression(ConstantExpression node) {
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index eb2f7d1..098e79d 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -96,7 +96,7 @@
_typeFlowAnalysis.environment.hierarchy);
@override
- DirectCallMetadata getDirectCall(TreeNode node, Member target,
+ DirectCallMetadata getDirectCall(TreeNode node, Member interfaceTarget,
{bool setter = false}) {
final callSite = _typeFlowAnalysis.callSite(node);
if (callSite != null) {
@@ -115,10 +115,12 @@
final TypeFlowAnalysis _typeFlowAnalysis;
final InferredTypeMetadataRepository _inferredTypeMetadata;
final UnreachableNodeMetadataRepository _unreachableNodeMetadata;
+ final DartType _intType;
AnnotateKernel(Component component, this._typeFlowAnalysis)
: _inferredTypeMetadata = new InferredTypeMetadataRepository(),
- _unreachableNodeMetadata = new UnreachableNodeMetadataRepository() {
+ _unreachableNodeMetadata = new UnreachableNodeMetadataRepository(),
+ _intType = _typeFlowAnalysis.environment.intType {
component.addMetadataRepository(_inferredTypeMetadata);
component.addMetadataRepository(_unreachableNodeMetadata);
}
@@ -127,23 +129,25 @@
assertx(type != null);
Class concreteClass;
+ bool isInt = false;
final nullable = type is NullableType;
if (nullable) {
- final baseType = (type as NullableType).baseType;
-
- if (baseType == const EmptyType()) {
- concreteClass = _typeFlowAnalysis.environment.coreTypes.nullClass;
- } else {
- concreteClass =
- baseType.getConcreteClass(_typeFlowAnalysis.hierarchyCache);
- }
- } else {
- concreteClass = type.getConcreteClass(_typeFlowAnalysis.hierarchyCache);
+ type = (type as NullableType).baseType;
}
- if ((concreteClass != null) || !nullable) {
- return new InferredType(concreteClass, nullable);
+ if (nullable && type == const EmptyType()) {
+ concreteClass = _typeFlowAnalysis.environment.coreTypes.nullClass;
+ } else {
+ concreteClass = type.getConcreteClass(_typeFlowAnalysis.hierarchyCache);
+
+ if (concreteClass == null) {
+ isInt = type.isSubtypeOf(_typeFlowAnalysis.hierarchyCache, _intType);
+ }
+ }
+
+ if ((concreteClass != null) || !nullable || isInt) {
+ return new InferredType(concreteClass, nullable, isInt);
}
return null;
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 2100c02..c2da60f 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -95,6 +95,8 @@
Class getConcreteClass(TypeHierarchy typeHierarchy) => null;
+ bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) => false;
+
@override
Type getComputedType(List<Type> types) => this;
@@ -168,6 +170,10 @@
String toString() => "${baseType}?";
@override
+ bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) =>
+ baseType.isSubtypeOf(typeHierarchy, dartType);
+
+ @override
int get order => TypeOrder.Nullable.index;
@override
@@ -279,6 +285,10 @@
String toString() => "_T ${types}";
@override
+ bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) =>
+ types.every((ConcreteType t) => t.isSubtypeOf(typeHierarchy, dartType));
+
+ @override
int get order => TypeOrder.Set.index;
static List<ConcreteType> _unionLists(
@@ -397,6 +407,10 @@
.getConcreteClass(typeHierarchy);
@override
+ bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) =>
+ typeHierarchy.isSubtype(this.dartType, dartType);
+
+ @override
int get hashCode => (dartType.hashCode + 37) & kHashMask;
@override
@@ -505,6 +519,10 @@
(dartType as InterfaceType).classNode;
@override
+ bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) =>
+ typeHierarchy.isSubtype(this.dartType, dartType);
+
+ @override
int get hashCode => (classId.hashCode ^ 0x1234) & kHashMask;
@override
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/annotation.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/annotation.dart.expect
index 925603f..fde6a80 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/annotation.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/annotation.dart.expect
@@ -37,7 +37,7 @@
}
static method foo([@vm.inferred-type.metadata=dart.core::Null?] (core::List<core::int>) → void a) → core::int {
@self::VarAnnotation::•() core::int x = 2;
- return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] x.{core::num::+}(2);
+ return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int?] x.{core::num::+}(2);
}
@self::ParametrizedAnnotation::•<core::Null>(null)
static method main(core::List<core::String> args) → dynamic {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart b/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart
new file mode 100644
index 0000000..f7a9da8
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart
@@ -0,0 +1,35 @@
+bool isPrime(var n) {
+ if (n < 2) return false;
+ for (var i = 2; i * i <= n; i++) {
+ if (n % i == 0) return false;
+ }
+ return true;
+}
+
+int nThPrimeNumber(int n) {
+ int counter = 0;
+ for (var i = 1;; i++) {
+ if (isPrime(i)) counter++;
+ if (counter == n) {
+ return i;
+ }
+ }
+}
+
+void run() {
+ int e = 611953;
+ int p = nThPrimeNumber(50000);
+ if (p != e) {
+ throw Exception("Unexpected result: $p != $e");
+ }
+}
+
+main(List<String> args) {
+ Stopwatch timer = new Stopwatch()..start();
+ for (int i = 0; i < 100; ++i) {
+ run();
+ }
+ timer.stop();
+
+ print("Elapsed ${timer.elapsedMilliseconds}ms");
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect
new file mode 100644
index 0000000..46769b4
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect
@@ -0,0 +1,38 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+
+static method isPrime([@vm.inferred-type.metadata=int?] dynamic n) → core::bool {
+ if([@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] [@vm.inferred-type.metadata=dart.core::bool] n.<(2) as{TypeError} core::bool)
+ return false;
+ for (core::int i = 2; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<=??] [@vm.inferred-type.metadata=dart.core::bool] [@vm.direct-call.metadata=dart.core::_IntegerImplementation::*??] [@vm.inferred-type.metadata=int?] i.{core::num::*}(i).{core::num::<=}(n as{TypeError} core::num); i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] [@vm.inferred-type.metadata=int?] i.{core::num::+}(1)) {
+ if([@vm.inferred-type.metadata=dart.core::bool] [@vm.direct-call.metadata=dart.core::_IntegerImplementation::%??] [@vm.inferred-type.metadata=int?] n.%(i).{core::Object::==}(0))
+ return false;
+ }
+ return true;
+}
+static method nThPrimeNumber([@vm.inferred-type.metadata=int] core::int n) → core::int {
+ core::int counter = 0;
+ for (core::int i = 1; ; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] [@vm.inferred-type.metadata=int?] i.{core::num::+}(1)) {
+ if([@vm.inferred-type.metadata=dart.core::bool] self::isPrime(i))
+ counter = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] [@vm.inferred-type.metadata=int?] counter.{core::num::+}(1);
+ if([@vm.inferred-type.metadata=dart.core::bool] counter.{core::num::==}(n)) {
+ return i;
+ }
+ }
+}
+static method run() → void {
+ core::int e = 611953;
+ core::int p = [@vm.inferred-type.metadata=int?] self::nThPrimeNumber(50000);
+ if(![@vm.inferred-type.metadata=dart.core::bool] p.{core::num::==}(e)) {
+ throw core::Exception::•("Unexpected result: ${p} != ${e}");
+ }
+}
+static method main(core::List<core::String> args) → dynamic {
+ core::Stopwatch timer = let final core::Stopwatch #t1 = new core::Stopwatch::•() in let final dynamic #t2 = [@vm.direct-call.metadata=dart.core::Stopwatch::start] #t1.{core::Stopwatch::start}() in #t1;
+ for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] [@vm.inferred-type.metadata=dart.core::bool] i.{core::num::<}(100); i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] [@vm.inferred-type.metadata=int?] i.{core::num::+}(1)) {
+ self::run();
+ }
+ [@vm.direct-call.metadata=dart.core::Stopwatch::stop] timer.{core::Stopwatch::stop}();
+ core::print("Elapsed ${[@vm.direct-call.metadata=dart.core::Stopwatch::elapsedMilliseconds] timer.{core::Stopwatch::elapsedMilliseconds}}ms");
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect
index 3b702f1..e158e50 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect
@@ -4,20 +4,20 @@
import "dart:typed_data" as typ;
class _Vector extends core::Object {
-[@vm.inferred-type.metadata=!] final field core::int _offset;
-[@vm.inferred-type.metadata=!] final field core::int _length;
+[@vm.inferred-type.metadata=int] final field core::int _offset;
+[@vm.inferred-type.metadata=int] final field core::int _length;
[@vm.inferred-type.metadata=dart.typed_data::_Float64List] final field core::List<core::double> _elements;
- constructor •([@vm.inferred-type.metadata=!] core::int size) → void
+ constructor •([@vm.inferred-type.metadata=int] core::int size) → void
: self::_Vector::_offset = 0, self::_Vector::_length = size, self::_Vector::_elements = [@vm.inferred-type.metadata=dart.typed_data::_Float64List] typ::Float64List::•(size), super core::Object::•()
;
operator [](core::int i) → core::double
- return [@vm.direct-call.metadata=dart.typed_data::_Float64List::[]] [@vm.inferred-type.metadata=dart.core::_Double] [@vm.direct-call.metadata=#lib::_Vector::_elements] [@vm.inferred-type.metadata=dart.typed_data::_Float64List] this.{self::_Vector::_elements}.{core::List::[]}([@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] i.{core::num::+}([@vm.direct-call.metadata=#lib::_Vector::_offset] [@vm.inferred-type.metadata=!] this.{self::_Vector::_offset}));
+ return [@vm.direct-call.metadata=dart.typed_data::_Float64List::[]] [@vm.inferred-type.metadata=dart.core::_Double] [@vm.direct-call.metadata=#lib::_Vector::_elements] [@vm.inferred-type.metadata=dart.typed_data::_Float64List] this.{self::_Vector::_elements}.{core::List::[]}([@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] [@vm.inferred-type.metadata=int?] i.{core::num::+}([@vm.direct-call.metadata=#lib::_Vector::_offset] [@vm.inferred-type.metadata=int] this.{self::_Vector::_offset}));
operator []=([@vm.inferred-type.metadata=!] core::int i, core::double value) → void {
- let dynamic #t1 = [@vm.direct-call.metadata=#lib::_Vector::_elements] [@vm.inferred-type.metadata=dart.typed_data::_Float64List] this.{self::_Vector::_elements} in let dynamic #t2 = i in let dynamic #t3 = [@vm.direct-call.metadata=#lib::_Vector::_offset] [@vm.inferred-type.metadata=!] this.{self::_Vector::_offset} in throw "Attempt to execute code removed by Dart AOT compiler (TFA)";
+ let dynamic #t1 = [@vm.direct-call.metadata=#lib::_Vector::_elements] [@vm.inferred-type.metadata=dart.typed_data::_Float64List] this.{self::_Vector::_elements} in let dynamic #t2 = i in let dynamic #t3 = [@vm.direct-call.metadata=#lib::_Vector::_offset] [@vm.inferred-type.metadata=int] this.{self::_Vector::_offset} in throw "Attempt to execute code removed by Dart AOT compiler (TFA)";
}
operator *([@vm.inferred-type.metadata=#lib::_Vector?] self::_Vector a) → core::double {
core::double result = 0.0;
- for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] [@vm.inferred-type.metadata=dart.core::bool] i.{core::num::<}([@vm.direct-call.metadata=#lib::_Vector::_length] [@vm.inferred-type.metadata=!] this.{self::_Vector::_length}); i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] i.{core::num::+}(1))
+ for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] [@vm.inferred-type.metadata=dart.core::bool] i.{core::num::<}([@vm.direct-call.metadata=#lib::_Vector::_length] [@vm.inferred-type.metadata=int] this.{self::_Vector::_length}); i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] [@vm.inferred-type.metadata=int?] i.{core::num::+}(1))
result = [@vm.direct-call.metadata=dart.core::_Double::+??] [@vm.inferred-type.metadata=dart.core::_Double] result.{core::double::+}([@vm.direct-call.metadata=dart.core::_Double::*] [@vm.inferred-type.metadata=dart.core::_Double] [@vm.direct-call.metadata=#lib::_Vector::[]] [@vm.inferred-type.metadata=dart.core::_Double] this.{self::_Vector::[]}(i).{core::double::*}([@vm.direct-call.metadata=#lib::_Vector::[]??] [@vm.inferred-type.metadata=dart.core::_Double] a.{self::_Vector::[]}(i)));
return result;
}
@@ -26,7 +26,7 @@
[@vm.inferred-type.metadata=dart.core::_Double?]static field core::double x = 0.0;
static method main(core::List<core::String> args) → dynamic {
core::Stopwatch timer = let final core::Stopwatch #t4 = new core::Stopwatch::•() in let final dynamic #t5 = [@vm.direct-call.metadata=dart.core::Stopwatch::start] #t4.{core::Stopwatch::start}() in #t4;
- for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] [@vm.inferred-type.metadata=dart.core::bool] i.{core::num::<}(100000000); i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] i.{core::num::+}(1)) {
+ for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] [@vm.inferred-type.metadata=dart.core::bool] i.{core::num::<}(100000000); i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] [@vm.inferred-type.metadata=int?] i.{core::num::+}(1)) {
self::x = [@vm.direct-call.metadata=dart.core::_Double::+??] [@vm.inferred-type.metadata=dart.core::_Double] [@vm.inferred-type.metadata=dart.core::_Double?] self::x.{core::double::+}([@vm.direct-call.metadata=#lib::_Vector::*??] [@vm.inferred-type.metadata=dart.core::_Double] [@vm.inferred-type.metadata=#lib::_Vector?] self::v.{self::_Vector::*}([@vm.inferred-type.metadata=#lib::_Vector?] self::v));
}
[@vm.direct-call.metadata=dart.core::Stopwatch::stop] timer.{core::Stopwatch::stop}();
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_while_processing.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_while_processing.dart.expect
index 2d95c84..240802d 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_while_processing.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_while_processing.dart.expect
@@ -28,7 +28,7 @@
return new self::Point::•([@vm.direct-call.metadata=#lib::Point::x] [@vm.inferred-type.metadata=!] this.{self::Point::x});
}
static method getX([@vm.inferred-type.metadata=#lib::Point] dynamic point) → dynamic {
- point.x;
+ [@vm.direct-call.metadata=#lib::Point::x] point.x;
}
static method main() → dynamic {
self::Point a = new self::Point::•(new self::T1::•());
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
index 01c1009..86a3d0f 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
@@ -51,7 +51,7 @@
return [@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withoutType("get:bar", const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}), false)) as{TypeError} dynamic;
no-such-method-forwarder method foo() → dynamic
return [@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withoutType("foo", const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}), false)) as{TypeError} dynamic;
- no-such-method-forwarder method bazz([@vm.inferred-type.metadata=!] dynamic a1, [@vm.inferred-type.metadata=!] dynamic a2, [@vm.inferred-type.metadata=!] dynamic a3, [[@vm.inferred-type.metadata=!] dynamic a4 = null, [@vm.inferred-type.metadata=dart.core::Null?] dynamic a5 = null]) → dynamic
+ no-such-method-forwarder method bazz([@vm.inferred-type.metadata=int] dynamic a1, [@vm.inferred-type.metadata=int] dynamic a2, [@vm.inferred-type.metadata=int] dynamic a3, [[@vm.inferred-type.metadata=int] dynamic a4 = null, [@vm.inferred-type.metadata=dart.core::Null?] dynamic a5 = null]) → dynamic
return [@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withoutType("bazz", const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[a1, a2, a3, a4, a5]), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}), false)) as{TypeError} dynamic;
}
abstract class C extends core::Object {
@@ -70,7 +70,7 @@
return [@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withoutType("get:bar", const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}), false)) as{TypeError} dynamic;
no-such-method-forwarder method foo() → dynamic
return [@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withoutType("foo", const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}), false)) as{TypeError} dynamic;
- no-such-method-forwarder method bazz([@vm.inferred-type.metadata=!] dynamic a1, [@vm.inferred-type.metadata=!] dynamic a2, [@vm.inferred-type.metadata=!] dynamic a3, [[@vm.inferred-type.metadata=!] dynamic a4 = null, [@vm.inferred-type.metadata=dart.core::Null?] dynamic a5 = null]) → dynamic
+ no-such-method-forwarder method bazz([@vm.inferred-type.metadata=int] dynamic a1, [@vm.inferred-type.metadata=int] dynamic a2, [@vm.inferred-type.metadata=int] dynamic a3, [[@vm.inferred-type.metadata=int] dynamic a4 = null, [@vm.inferred-type.metadata=dart.core::Null?] dynamic a5 = null]) → dynamic
return [@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withoutType("bazz", const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[a1, a2, a3, a4, a5]), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}), false)) as{TypeError} dynamic;
}
class E extends core::Object implements self::A {
@@ -103,7 +103,7 @@
synthetic constructor •() → void
: super core::Object::•()
;
- method foo({[@vm.inferred-type.metadata=!] dynamic left = null, [@vm.inferred-type.metadata=!] dynamic right = null}) → dynamic
+ method foo({[@vm.inferred-type.metadata=int] dynamic left = null, [@vm.inferred-type.metadata=int] dynamic right = null}) → dynamic
return new self::T6::•();
method noSuchMethod(core::Invocation invocation) → dynamic {
return new self::T7::•();
@@ -130,6 +130,6 @@
dynamic gg = new self::G::•();
core::print([@vm.inferred-type.metadata=#lib::T5] gg.noSuchMethod(null, null));
dynamic hh = new self::H::•();
- core::print([@vm.inferred-type.metadata=#lib::T6] hh.foo(right: 2, left: 1));
+ core::print([@vm.direct-call.metadata=#lib::H::foo] [@vm.inferred-type.metadata=#lib::T6] hh.foo(right: 2, left: 1));
core::print([@vm.inferred-type.metadata=#lib::T7] hh.foo(left: 1, top: 2));
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
index 18cbd9d4..1ad7392 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
@@ -16,7 +16,7 @@
synthetic constructor •() → void
: super core::Object::•()
;
- method call([dynamic a1 = null, dynamic a2 = null, dynamic a3 = null, dynamic a4 = null, [@vm.inferred-type.metadata=#lib::T1?] dynamic a5 = null]) → void {
+ method call([dynamic a1 = null, dynamic a2 = null, dynamic a3 = null, [@vm.inferred-type.metadata=int?] dynamic a4 = null, [@vm.inferred-type.metadata=#lib::T1?] dynamic a5 = null]) → void {
[@vm.direct-call.metadata=#lib::A1::foo] this.{self::A1::foo} = a5 as{TypeError} self::T1;
}
}
@@ -39,7 +39,7 @@
synthetic constructor •() → void
: super core::Object::•()
;
- method call([dynamic a1 = null, dynamic a2 = null, dynamic a3 = null, dynamic a4 = null, dynamic a5 = null, [@vm.inferred-type.metadata=#lib::T2?] dynamic a6 = null]) → void {
+ method call([dynamic a1 = null, dynamic a2 = null, dynamic a3 = null, [@vm.inferred-type.metadata=int?] dynamic a4 = null, [@vm.inferred-type.metadata=int?] dynamic a5 = null, [@vm.inferred-type.metadata=#lib::T2?] dynamic a6 = null]) → void {
[@vm.direct-call.metadata=#lib::A2::foo] this.{self::A2::foo} = a6;
}
}
@@ -56,7 +56,7 @@
: super self::B2Base::•()
;
method doSuperCall() → void {
- [@vm.inferred-type.metadata=#lib::A2] super.{self::B2Base::aa2}.call(1, 2, 3, 4, 5, new self::T2::•());
+ [@vm.direct-call.metadata=#lib::A2::call] [@vm.inferred-type.metadata=#lib::A2] super.{self::B2Base::aa2}.call(1, 2, 3, 4, 5, new self::T2::•());
}
}
class T3 extends core::Object {
@@ -72,7 +72,7 @@
synthetic constructor •() → void
: super core::Object::•()
;
- method call([dynamic a1 = null, dynamic a2 = null, dynamic a3 = null, dynamic a4 = null, dynamic a5 = null, dynamic a6 = null, [@vm.inferred-type.metadata=#lib::T3?] dynamic a7 = null]) → void {
+ method call([dynamic a1 = null, dynamic a2 = null, dynamic a3 = null, [@vm.inferred-type.metadata=int?] dynamic a4 = null, [@vm.inferred-type.metadata=int?] dynamic a5 = null, [@vm.inferred-type.metadata=int?] dynamic a6 = null, [@vm.inferred-type.metadata=#lib::T3?] dynamic a7 = null]) → void {
[@vm.direct-call.metadata=#lib::A3::foo] this.{self::A3::foo} = a7;
}
}
@@ -95,7 +95,7 @@
synthetic constructor •() → void
: super core::Object::•()
;
- method call([dynamic a1 = null, dynamic a2 = null, dynamic a3 = null, dynamic a4 = null, dynamic a5 = null, dynamic a6 = null, dynamic a7 = null, [@vm.inferred-type.metadata=#lib::T4?] dynamic a8 = null]) → void {
+ method call([dynamic a1 = null, dynamic a2 = null, dynamic a3 = null, [@vm.inferred-type.metadata=int?] dynamic a4 = null, [@vm.inferred-type.metadata=int?] dynamic a5 = null, [@vm.inferred-type.metadata=int?] dynamic a6 = null, [@vm.inferred-type.metadata=int?] dynamic a7 = null, [@vm.inferred-type.metadata=#lib::T4?] dynamic a8 = null]) → void {
[@vm.direct-call.metadata=#lib::A4::foo] this.{self::A4::foo} = a8;
}
}
@@ -123,7 +123,7 @@
self::B2 bb = new self::B2::•();
[@vm.direct-call.metadata=#lib::B2::doSuperCall] bb.{self::B2::doSuperCall}();
self::ok = false;
- [@vm.inferred-type.metadata=#lib::T2?] [@vm.direct-call.metadata=#lib::B2Base::aa2] [@vm.inferred-type.metadata=#lib::A2] bb.{self::B2Base::aa2}.foo.doTest2();
+ [@vm.direct-call.metadata=#lib::T2::doTest2??] [@vm.direct-call.metadata=#lib::A2::foo] [@vm.inferred-type.metadata=#lib::T2?] [@vm.direct-call.metadata=#lib::B2Base::aa2] [@vm.inferred-type.metadata=#lib::A2] bb.{self::B2Base::aa2}.foo.doTest2();
exp::Expect::isTrue([@vm.inferred-type.metadata=dart.core::bool?] self::ok);
}
static method getDynamic3() → dynamic
@@ -131,7 +131,7 @@
static method test3() → void {
self::getDynamic3().aa3(1, 2, 3, 4, 5, 6, new self::T3::•());
self::ok = false;
- [@vm.inferred-type.metadata=#lib::T3?] [@vm.inferred-type.metadata=#lib::A3] [@vm.inferred-type.metadata=#lib::B3?] self::bb3.aa3.foo.doTest3();
+ [@vm.direct-call.metadata=#lib::T3::doTest3??] [@vm.direct-call.metadata=#lib::A3::foo] [@vm.inferred-type.metadata=#lib::T3?] [@vm.direct-call.metadata=#lib::B3::aa3??] [@vm.inferred-type.metadata=#lib::A3] [@vm.inferred-type.metadata=#lib::B3?] self::bb3.aa3.foo.doTest3();
exp::Expect::isTrue([@vm.inferred-type.metadata=dart.core::bool?] self::ok);
}
static method getDynamic4() → dynamic
@@ -139,7 +139,7 @@
static method test4() → void {
self::getDynamic4().aa4(1, 2, 3, 4, 5, 6, 7, new self::T4::•());
self::ok = false;
- [@vm.inferred-type.metadata=#lib::T4?] [@vm.inferred-type.metadata=#lib::A4] self::getDynamic4().aa4.foo.doTest4();
+ [@vm.direct-call.metadata=#lib::T4::doTest4??] [@vm.direct-call.metadata=#lib::A4::foo] [@vm.inferred-type.metadata=#lib::T4?] [@vm.inferred-type.metadata=#lib::A4] self::getDynamic4().aa4.foo.doTest4();
exp::Expect::isTrue([@vm.inferred-type.metadata=dart.core::bool?] self::ok);
}
static method main() → void {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
index 002fca8..8492698 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
@@ -12,7 +12,7 @@
: super self::A::•()
;
method foo() → core::int
- return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] 1.{core::num::+}([@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
+ return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
}
class TearOffDynamicMethod extends core::Object {
field dynamic bazz;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
index 00d3f0f..18c3870 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
@@ -13,7 +13,7 @@
: super self::A::•()
;
method foo() → core::int
- return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] 1.{core::num::+}([@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
+ return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int?] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int?] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
}
class TearOffInterfaceMethod extends core::Object {
field dynamic bazz;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
index 72d0517..689ae8c 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
@@ -13,14 +13,14 @@
: super self::A::•()
;
method foo() → core::int
- return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] 1.{core::num::+}([@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
+ return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int?] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int?] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
}
abstract class Base extends core::Object {
synthetic constructor •() → void
: super core::Object::•()
;
method foo() → core::int
- return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] 3.{core::num::+}([@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
+ return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int?] 3.{core::num::+}([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int?] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
method doCall(dynamic x) → core::int
return x.call() as{TypeError} core::int;
}
@@ -29,7 +29,7 @@
: super self::Base::•()
;
method bar() → core::int
- return [@vm.direct-call.metadata=#lib::Base::doCall] this.{self::Base::doCall}(super.{self::Base::foo});
+ return [@vm.direct-call.metadata=#lib::Base::doCall] [@vm.inferred-type.metadata=int?] this.{self::Base::doCall}(super.{self::Base::foo});
}
[@vm.inferred-type.metadata=#lib::B?]static field self::A aa = new self::B::•();
static method knownResult() → dynamic
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index 7b6458c..c1d4f2b 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -957,9 +957,10 @@
if (block_->IsGraphEntry()) {
inferred_type = param->parameter_type();
}
- // Best bet: use inferred type if it has a concrete class.
- if ((inferred_type != NULL) &&
- (inferred_type->ToNullableCid() != kDynamicCid)) {
+ // Best bet: use inferred type if it is a concrete class or int.
+ if ((inferred_type != nullptr) &&
+ ((inferred_type->ToNullableCid() != kDynamicCid) ||
+ inferred_type->IsNullableInt())) {
TraceStrongModeType(this, inferred_type);
return *inferred_type;
}
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index d51b1c9..bda808c 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -359,8 +359,7 @@
checked_argument_count, ic_data_array_, GetNextDeoptId(),
interface_target);
if ((result_type != NULL) && !result_type->IsTrivial()) {
- call->SetResultType(Z, CompileType::CreateNullable(result_type->nullable,
- result_type->cid));
+ call->SetResultType(Z, result_type->ToCompileType(Z));
}
Push(call);
return Fragment(call);
@@ -553,8 +552,7 @@
}
}
if ((result_type != NULL) && !result_type->IsTrivial()) {
- call->SetResultType(Z, CompileType::CreateNullable(result_type->nullable,
- result_type->cid));
+ call->SetResultType(Z, result_type->ToCompileType(Z));
}
}
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 586eedb..02047bd 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -1607,17 +1607,18 @@
intptr_t node_offset) {
const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
if (md_offset < 0) {
- return InferredTypeMetadata(kDynamicCid, true);
+ return InferredTypeMetadata(kDynamicCid,
+ InferredTypeMetadata::kFlagNullable);
}
AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
md_offset);
const NameIndex kernel_name = helper_->ReadCanonicalNameReference();
- const bool nullable = helper_->ReadBool();
+ const uint8_t flags = helper_->ReadByte();
if (H.IsRoot(kernel_name)) {
- return InferredTypeMetadata(kDynamicCid, nullable);
+ return InferredTypeMetadata(kDynamicCid, flags);
}
const Class& klass =
@@ -1631,7 +1632,7 @@
cid = kDynamicCid;
}
- return InferredTypeMetadata(cid, nullable);
+ return InferredTypeMetadata(cid, flags);
}
ProcedureAttributesMetadataHelper::ProcedureAttributesMetadataHelper(
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 9a7fbf5..ea2f79b 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -5,6 +5,7 @@
#ifndef RUNTIME_VM_COMPILER_FRONTEND_KERNEL_TRANSLATION_HELPER_H_
#define RUNTIME_VM_COMPILER_FRONTEND_KERNEL_TRANSLATION_HELPER_H_
+#include "vm/compiler/backend/il.h" // For CompileType.
#include "vm/kernel.h"
#include "vm/kernel_binary.h"
#include "vm/object.h"
@@ -831,13 +832,31 @@
};
struct InferredTypeMetadata {
- InferredTypeMetadata(intptr_t cid_, bool nullable_)
- : cid(cid_), nullable(nullable_) {}
+ enum Flag {
+ kFlagNullable = 1 << 0,
+ kFlagInt = 1 << 1,
+ };
+
+ InferredTypeMetadata(intptr_t cid_, uint8_t flags_)
+ : cid(cid_), flags(flags_) {}
const intptr_t cid;
- const bool nullable;
+ const uint8_t flags;
- bool IsTrivial() const { return (cid == kDynamicCid) && nullable; }
+ bool IsTrivial() const {
+ return (cid == kDynamicCid) && (flags == kFlagNullable);
+ }
+ bool IsNullable() const { return (flags & kFlagNullable) != 0; }
+ bool IsInt() const { return (flags & kFlagInt) != 0; }
+
+ CompileType ToCompileType(Zone* zone) const {
+ if (IsInt()) {
+ return CompileType::FromAbstractType(
+ Type::ZoneHandle(zone, Type::IntType()), IsNullable());
+ } else {
+ return CompileType::CreateNullable(IsNullable(), cid);
+ }
+ }
};
// Helper class which provides access to inferred type metadata.
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 9c50544..d78f149 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -1482,8 +1482,7 @@
const InferredTypeMetadata* param_type_md /* = NULL */) {
CompileType* param_type = NULL;
if ((param_type_md != NULL) && !param_type_md->IsTrivial()) {
- param_type = new (Z) CompileType(CompileType::CreateNullable(
- param_type_md->nullable, param_type_md->cid));
+ param_type = new (Z) CompileType(param_type_md->ToCompileType(Z));
}
return new (Z)
LocalVariable(declaration_pos, token_pos, name, type, param_type);