[vm] Handle new AST invocation nodes in VM kernel transformations
This change extends VM-specific kernel transformations to handle
new AST invocation nodes. The transformations may still generate
old nodes, but they should accept and handle new nodes coming from
the front-end.
TEST=Manual testing with new invocation nodes enabled.
Issue: https://github.com/dart-lang/sdk/issues/45340
Change-Id: I2de9f0eb00fcf844ba62fdc93b15a907c2d6b69d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/197443
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/kernel/lib/transformations/async.dart b/pkg/kernel/lib/transformations/async.dart
index f7b74c7..d80784a 100644
--- a/pkg/kernel/lib/transformations/async.dart
+++ b/pkg/kernel/lib/transformations/async.dart
@@ -159,6 +159,7 @@
TreeNode visitInvalidExpression(InvalidExpression expr) => nullary(expr);
TreeNode visitSuperPropertyGet(SuperPropertyGet expr) => nullary(expr);
TreeNode visitStaticGet(StaticGet expr) => nullary(expr);
+ TreeNode visitStaticTearOff(StaticTearOff expr) => nullary(expr);
TreeNode visitRethrow(Rethrow expr) => nullary(expr);
// Getting a final or const variable is not an effect so it can be evaluated
@@ -211,15 +212,32 @@
});
}
+ @override
TreeNode visitVariableSet(VariableSet expr) => unary(expr);
+ @override
TreeNode visitPropertyGet(PropertyGet expr) => unary(expr);
+ @override
+ TreeNode visitInstanceGet(InstanceGet expr) => unary(expr);
+ @override
+ TreeNode visitDynamicGet(DynamicGet expr) => unary(expr);
+ @override
+ TreeNode visitInstanceTearOff(InstanceTearOff expr) => unary(expr);
+ @override
+ TreeNode visitFunctionTearOff(FunctionTearOff expr) => unary(expr);
+ @override
TreeNode visitSuperPropertySet(SuperPropertySet expr) => unary(expr);
+ @override
TreeNode visitStaticSet(StaticSet expr) => unary(expr);
+ @override
TreeNode visitNot(Not expr) => unary(expr);
+ @override
TreeNode visitIsExpression(IsExpression expr) => unary(expr);
+ @override
TreeNode visitAsExpression(AsExpression expr) => unary(expr);
+ @override
TreeNode visitThrow(Throw expr) => unary(expr);
+ @override
TreeNode visitPropertySet(PropertySet expr) {
return transformTreeNode(expr, () {
expr.value = transform(expr.value)..parent = expr;
@@ -227,6 +245,22 @@
});
}
+ @override
+ TreeNode visitInstanceSet(InstanceSet expr) {
+ return transformTreeNode(expr, () {
+ expr.value = transform(expr.value)..parent = expr;
+ expr.receiver = transform(expr.receiver)..parent = expr;
+ });
+ }
+
+ @override
+ TreeNode visitDynamicSet(DynamicSet expr) {
+ return transformTreeNode(expr, () {
+ expr.value = transform(expr.value)..parent = expr;
+ expr.receiver = transform(expr.receiver)..parent = expr;
+ });
+ }
+
TreeNode visitArguments(Arguments args) {
for (var named in args.named.reversed) {
named.value = transform(named.value)..parent = named;
@@ -240,6 +274,7 @@
return args;
}
+ @override
TreeNode visitMethodInvocation(MethodInvocation expr) {
return transformTreeNode(expr, () {
visitArguments(expr.arguments);
@@ -247,6 +282,48 @@
});
}
+ @override
+ TreeNode visitInstanceInvocation(InstanceInvocation expr) {
+ return transformTreeNode(expr, () {
+ visitArguments(expr.arguments);
+ expr.receiver = transform(expr.receiver)..parent = expr;
+ });
+ }
+
+ @override
+ TreeNode visitLocalFunctionInvocation(LocalFunctionInvocation expr) {
+ return transformTreeNode(expr, () {
+ visitArguments(expr.arguments);
+ });
+ }
+
+ @override
+ TreeNode visitDynamicInvocation(DynamicInvocation expr) {
+ return transformTreeNode(expr, () {
+ visitArguments(expr.arguments);
+ expr.receiver = transform(expr.receiver)..parent = expr;
+ });
+ }
+
+ @override
+ TreeNode visitFunctionInvocation(FunctionInvocation expr) {
+ return transformTreeNode(expr, () {
+ visitArguments(expr.arguments);
+ expr.receiver = transform(expr.receiver)..parent = expr;
+ });
+ }
+
+ @override
+ TreeNode visitEqualsNull(EqualsNull expr) => unary(expr);
+
+ @override
+ TreeNode visitEqualsCall(EqualsCall expr) {
+ return transformTreeNode(expr, () {
+ expr.right = transform(expr.right)..parent = expr;
+ expr.left = transform(expr.left)..parent = expr;
+ });
+ }
+
TreeNode visitSuperMethodInvocation(SuperMethodInvocation expr) {
return transformTreeNode(expr, () {
visitArguments(expr.arguments);
diff --git a/pkg/vm/lib/transformations/call_site_annotator.dart b/pkg/vm/lib/transformations/call_site_annotator.dart
index e3722a1..c843506 100644
--- a/pkg/vm/lib/transformations/call_site_annotator.dart
+++ b/pkg/vm/lib/transformations/call_site_annotator.dart
@@ -55,6 +55,11 @@
receiverType: receiver.getStaticType(_staticTypeContext!));
}
+ void annotateWithFunctionType(TreeNode node, FunctionType type) {
+ _metadata.mapping[node] =
+ new CallSiteAttributesMetadata(receiverType: type);
+ }
+
@override
visitPropertySet(PropertySet node) {
super.visitPropertySet(node);
@@ -65,6 +70,15 @@
}
@override
+ visitInstanceSet(InstanceSet node) {
+ super.visitInstanceSet(node);
+
+ if (hasGenericCovariantParameters(node.interfaceTarget)) {
+ annotateWithType(node, node.receiver);
+ }
+ }
+
+ @override
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
@@ -76,6 +90,46 @@
}
}
+ @override
+ visitInstanceInvocation(InstanceInvocation node) {
+ super.visitInstanceInvocation(node);
+
+ // TODO(34162): We don't need to save the type here for calls, just whether
+ // or not it's a statically-checked call.
+ if (hasGenericCovariantParameters(node.interfaceTarget)) {
+ annotateWithType(node, node.receiver);
+ }
+ }
+
+ @override
+ visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+ super.visitLocalFunctionInvocation(node);
+
+ // TODO(34162): We don't need to save the type here for calls, just whether
+ // or not it's a statically-checked call.
+ annotateWithFunctionType(node, node.functionType);
+ }
+
+ @override
+ visitFunctionInvocation(FunctionInvocation node) {
+ super.visitFunctionInvocation(node);
+
+ // TODO(34162): We don't need to save the type here for calls, just whether
+ // or not it's a statically-checked call.
+ annotateWithType(node, node.receiver);
+ }
+
+ @override
+ visitEqualsCall(EqualsCall node) {
+ super.visitEqualsCall(node);
+
+ // TODO(34162): We don't need to save the type here for calls, just whether
+ // or not it's a statically-checked call.
+ if (hasGenericCovariantParameters(node.interfaceTarget)) {
+ annotateWithType(node, node.left);
+ }
+ }
+
/// Return [true] if the given list of [VariableDeclaration] contains
/// any annotated with generic-covariant-impl.
static bool containsGenericCovariantImpl(List<VariableDeclaration> decls) =>
diff --git a/pkg/vm/lib/transformations/devirtualization.dart b/pkg/vm/lib/transformations/devirtualization.dart
index a81d089..16189aa 100644
--- a/pkg/vm/lib/transformations/devirtualization.dart
+++ b/pkg/vm/lib/transformations/devirtualization.dart
@@ -101,11 +101,8 @@
super.visitLibrary(node);
}
- @override
- visitMethodInvocation(MethodInvocation node) {
- super.visitMethodInvocation(node);
-
- final Member target = node.interfaceTarget;
+ void _handleMethodInvocation(
+ TreeNode node, Member target, Arguments arguments) {
if (target != null && !isMethod(target)) {
return;
}
@@ -116,17 +113,42 @@
// check into an assertion once front-end implements all override checks.
if ((directCall != null) &&
isMethod(directCall.target) &&
- isLegalTargetForMethodInvocation(directCall.target, node.arguments) &&
+ isLegalTargetForMethodInvocation(directCall.target, arguments) &&
!hasExtraTargetForNull(directCall)) {
makeDirectCall(node, target, directCall);
}
}
@override
- visitPropertyGet(PropertyGet node) {
- super.visitPropertyGet(node);
+ visitMethodInvocation(MethodInvocation node) {
+ super.visitMethodInvocation(node);
+ _handleMethodInvocation(node, node.interfaceTarget, node.arguments);
+ }
- final Member target = node.interfaceTarget;
+ @override
+ visitInstanceInvocation(InstanceInvocation node) {
+ super.visitInstanceInvocation(node);
+ _handleMethodInvocation(node, node.interfaceTarget, node.arguments);
+ }
+
+ @override
+ visitDynamicInvocation(DynamicInvocation node) {
+ super.visitDynamicInvocation(node);
+ _handleMethodInvocation(node, null, node.arguments);
+ }
+
+ @override
+ visitEqualsCall(EqualsCall node) {
+ super.visitEqualsCall(node);
+
+ final target = node.interfaceTarget;
+ final DirectCallMetadata directCall = getDirectCall(node, target);
+ if (directCall != null && !directCall.checkReceiverForNull) {
+ makeDirectCall(node, target, directCall);
+ }
+ }
+
+ void _handlePropertyGet(TreeNode node, Member target) {
if (target != null && !isFieldOrGetter(target)) {
return;
}
@@ -141,16 +163,48 @@
}
@override
- visitPropertySet(PropertySet node) {
- super.visitPropertySet(node);
+ visitPropertyGet(PropertyGet node) {
+ super.visitPropertyGet(node);
+ _handlePropertyGet(node, node.interfaceTarget);
+ }
- final Member target = node.interfaceTarget;
+ @override
+ visitInstanceGet(InstanceGet node) {
+ super.visitInstanceGet(node);
+ _handlePropertyGet(node, node.interfaceTarget);
+ }
+
+ @override
+ visitDynamicGet(DynamicGet node) {
+ super.visitDynamicGet(node);
+ _handlePropertyGet(node, null);
+ }
+
+ void _handlePropertySet(TreeNode node, Member target) {
final DirectCallMetadata directCall =
getDirectCall(node, target, setter: true);
if (directCall != null) {
makeDirectCall(node, target, directCall);
}
}
+
+ @override
+ visitPropertySet(PropertySet node) {
+ super.visitPropertySet(node);
+ _handlePropertySet(node, node.interfaceTarget);
+ }
+
+ @override
+ visitInstanceSet(InstanceSet node) {
+ super.visitInstanceSet(node);
+ _handlePropertySet(node, node.interfaceTarget);
+ }
+
+ @override
+ visitDynamicSet(DynamicSet node) {
+ super.visitDynamicSet(node);
+ _handlePropertySet(node, null);
+ }
}
/// Devirtualization based on the closed-world class hierarchy analysis.
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index a094f53..153a07a 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -704,6 +704,44 @@
return node;
}
+ @override
+ visitInstanceInvocation(InstanceInvocation node) {
+ super.visitInstanceInvocation(node);
+
+ final Member target = node.interfaceTarget;
+ try {
+ if (target == elementAtMethod) {
+ final DartType pointerType =
+ node.receiver.getStaticType(_staticTypeContext);
+ final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
+
+ _ensureNativeTypeValid(nativeType, node, allowCompounds: true);
+
+ Expression inlineSizeOf = _inlineSizeOf(nativeType);
+ if (inlineSizeOf != null) {
+ // Generates `receiver.offsetBy(inlineSizeOfExpression)`.
+ return MethodInvocation(
+ node.receiver,
+ offsetByMethod.name,
+ Arguments([
+ MethodInvocation(
+ node.arguments.positional.single,
+ numMultiplication.name,
+ Arguments([inlineSizeOf]),
+ numMultiplication)
+ ]),
+ offsetByMethod);
+ }
+ }
+ } on _FfiStaticTypeError {
+ // It's OK to swallow the exception because the diagnostics issued will
+ // cause compilation to fail. By continuing, we can report more
+ // diagnostics before compilation ends.
+ }
+
+ return node;
+ }
+
DartType _pointerTypeGetTypeArg(DartType pointerType) {
return pointerType is InterfaceType ? pointerType.typeArguments[0] : null;
}
diff --git a/pkg/vm/lib/transformations/mixin_deduplication.dart b/pkg/vm/lib/transformations/mixin_deduplication.dart
index a328961..8cfc503 100644
--- a/pkg/vm/lib/transformations/mixin_deduplication.dart
+++ b/pkg/vm/lib/transformations/mixin_deduplication.dart
@@ -172,18 +172,51 @@
}
@override
+ visitInstanceGet(InstanceGet node) {
+ node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget)!;
+ super.visitInstanceGet(node);
+ }
+
+ @override
+ visitInstanceTearOff(InstanceTearOff node) {
+ node.interfaceTarget =
+ _resolveNewInterfaceTarget(node.interfaceTarget) as Procedure;
+ super.visitInstanceTearOff(node);
+ }
+
+ @override
visitPropertySet(PropertySet node) {
node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
super.visitPropertySet(node);
}
@override
+ visitInstanceSet(InstanceSet node) {
+ node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget)!;
+ super.visitInstanceSet(node);
+ }
+
+ @override
visitMethodInvocation(MethodInvocation node) {
node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
super.visitMethodInvocation(node);
}
@override
+ visitInstanceInvocation(InstanceInvocation node) {
+ node.interfaceTarget =
+ _resolveNewInterfaceTarget(node.interfaceTarget) as Procedure;
+ super.visitInstanceInvocation(node);
+ }
+
+ @override
+ visitEqualsCall(EqualsCall node) {
+ node.interfaceTarget =
+ _resolveNewInterfaceTarget(node.interfaceTarget) as Procedure;
+ super.visitEqualsCall(node);
+ }
+
+ @override
visitSuperPropertyGet(SuperPropertyGet node) {
node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
super.visitSuperPropertyGet(node);
diff --git a/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart b/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
index 9b7e27c..0f9284b 100644
--- a/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
+++ b/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
@@ -190,6 +190,28 @@
}
@override
+ visitInstanceInvocation(InstanceInvocation node) {
+ super.visitInstanceInvocation(node);
+ if (node.receiver is! ThisExpression) {
+ nonThisSelectors.add(new Selector.doInvoke(node.name));
+ }
+ }
+
+ @override
+ visitDynamicInvocation(DynamicInvocation node) {
+ super.visitDynamicInvocation(node);
+ dynamicSelectors.add(new Selector.doInvoke(node.name));
+ }
+
+ @override
+ visitEqualsCall(EqualsCall node) {
+ super.visitEqualsCall(node);
+ if (node.left is! ThisExpression) {
+ nonThisSelectors.add(new Selector.doInvoke(Name('==')));
+ }
+ }
+
+ @override
visitPropertyGet(PropertyGet node) {
super.visitPropertyGet(node);
@@ -209,6 +231,29 @@
}
@override
+ visitInstanceGet(InstanceGet node) {
+ super.visitInstanceGet(node);
+ if (node.receiver is! ThisExpression) {
+ nonThisSelectors.add(new Selector.doGet(node.name));
+ }
+ }
+
+ @override
+ visitDynamicGet(DynamicGet node) {
+ super.visitDynamicGet(node);
+ dynamicSelectors.add(new Selector.doGet(node.name));
+ }
+
+ @override
+ visitInstanceTearOff(InstanceTearOff node) {
+ super.visitInstanceTearOff(node);
+ if (node.receiver is! ThisExpression) {
+ nonThisSelectors.add(new Selector.doGet(node.name));
+ }
+ tearOffSelectors.add(new Selector.doInvoke(node.name));
+ }
+
+ @override
visitPropertySet(PropertySet node) {
super.visitPropertySet(node);
@@ -221,4 +266,18 @@
}
}
}
+
+ @override
+ visitInstanceSet(InstanceSet node) {
+ super.visitInstanceSet(node);
+ if (node.receiver is! ThisExpression) {
+ nonThisSelectors.add(new Selector.doSet(node.name));
+ }
+ }
+
+ @override
+ visitDynamicSet(DynamicSet node) {
+ super.visitDynamicSet(node);
+ dynamicSelectors.add(new Selector.doSet(node.name));
+ }
}
diff --git a/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart b/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart
index 7643e45..865f56d 100644
--- a/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart
+++ b/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart
@@ -143,7 +143,8 @@
Statistics.protobufMetadataFieldsPruned += cls.numberOfFieldsPruned;
}
- bool _isUnusedMetadata(_MessageClass cls, MethodInvocation node) {
+ bool _isUnusedMetadataMethodInvocation(
+ _MessageClass cls, MethodInvocation node) {
if (node.interfaceTarget != null &&
node.interfaceTarget.enclosingClass == _builderInfoClass &&
fieldAddingMethods.contains(node.name.text)) {
@@ -152,6 +153,15 @@
}
return false;
}
+
+ bool _isUnusedMetadata(_MessageClass cls, InstanceInvocation node) {
+ if (node.interfaceTarget.enclosingClass == _builderInfoClass &&
+ fieldAddingMethods.contains(node.name.text)) {
+ final tagNumber = (node.arguments.positional[0] as IntLiteral).value;
+ return !cls._usedTags.contains(tagNumber);
+ }
+ return false;
+ }
}
class _MessageClass {
@@ -170,7 +180,7 @@
@override
TreeNode visitMethodInvocation(MethodInvocation node) {
- if (!ph._isUnusedMetadata(cls, node)) {
+ if (!ph._isUnusedMetadataMethodInvocation(cls, node)) {
super.visitMethodInvocation(node);
return node;
}
@@ -197,4 +207,34 @@
ph._builderInfoAddMethod)
..fileOffset = node.fileOffset;
}
+
+ @override
+ TreeNode visitInstanceInvocation(InstanceInvocation node) {
+ if (!ph._isUnusedMetadata(cls, node)) {
+ super.visitInstanceInvocation(node);
+ return node;
+ }
+ // Replace the field metadata method with a dummy call to
+ // `BuilderInfo.add`. This is to preserve the index calculations when
+ // removing a field.
+ // Change the tag-number to 0. Otherwise the decoder will get confused.
+ ++numberOfFieldsPruned;
+ return MethodInvocation(
+ node.receiver,
+ ph._builderInfoAddMethod.name,
+ Arguments(
+ <Expression>[
+ IntLiteral(0), // tagNumber
+ NullLiteral(), // name
+ NullLiteral(), // fieldType
+ NullLiteral(), // defaultOrMaker
+ NullLiteral(), // subBuilder
+ NullLiteral(), // valueOf
+ NullLiteral(), // enumValues
+ ],
+ types: <DartType>[const NullType()],
+ ),
+ ph._builderInfoAddMethod)
+ ..fileOffset = node.fileOffset;
+ }
}
diff --git a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
index c6c7608..709604c 100644
--- a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
+++ b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
@@ -233,7 +233,8 @@
shaker.typeFlowAnalysis.nativeCodeOracle
.isMemberReferencedFromNativeCode(member) ||
shaker.typeFlowAnalysis.nativeCodeOracle.isRecognized(member) ||
- getExternalName(member) != null) {
+ getExternalName(member) != null ||
+ member.name.text == '==') {
info.eligible = false;
}
}
@@ -302,6 +303,12 @@
}
@override
+ void visitInstanceInvocation(InstanceInvocation node) {
+ collectCall(node.interfaceTarget, node.arguments);
+ super.visitInstanceInvocation(node);
+ }
+
+ @override
void visitSuperMethodInvocation(SuperMethodInvocation node) {
collectCall(node.interfaceTarget, node.arguments);
super.visitSuperMethodInvocation(node);
@@ -639,6 +646,12 @@
}
@override
+ void visitInstanceInvocation(InstanceInvocation node) {
+ super.visitInstanceInvocation(node);
+ transformCall(node.interfaceTarget, node, node.receiver, node.arguments);
+ }
+
+ @override
void visitSuperMethodInvocation(SuperMethodInvocation node) {
super.visitSuperMethodInvocation(node);
transformCall(node.interfaceTarget, node, null, node.arguments);
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 34c375b..a20c840 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -1131,7 +1131,8 @@
TypeExpr _makeNarrowNotNull(TreeNode node, TypeExpr arg) {
assert(node is NullCheck ||
- node is MethodInvocation && isComparisonWithNull(node));
+ node is MethodInvocation && isComparisonWithNull(node) ||
+ node is EqualsNull);
if (arg is NarrowNotNull) {
nullTests[node] = arg;
return arg;
@@ -1388,6 +1389,40 @@
_variableValues = null;
return;
}
+ } else if (node is EqualsCall && node.left is VariableGet) {
+ final lhs = node.left as VariableGet;
+ final rhs = node.right;
+ if ((rhs is IntLiteral &&
+ _isSubtype(lhs.variable.type,
+ _environment.coreTypes.intLegacyRawType)) ||
+ (rhs is StringLiteral &&
+ _isSubtype(lhs.variable.type,
+ _environment.coreTypes.stringLegacyRawType)) ||
+ (rhs is ConstantExpression &&
+ !_hasOverriddenEquals(lhs.variable.type))) {
+ // 'x == c', where x is a variable and c is a constant.
+ _addUse(_visit(node));
+ final int varIndex = _variablesInfo.varIndex[lhs.variable];
+ if (_variableCells[varIndex] == null) {
+ trueState[varIndex] = _visit(rhs);
+ }
+ _variableValues = null;
+ return;
+ }
+ } else if (node is EqualsNull && node.expression is VariableGet) {
+ final lhs = node.expression as VariableGet;
+ // 'x == null', where x is a variable.
+ final expr = _visit(lhs);
+ _makeCall(node, DirectSelector(_environment.coreTypes.objectEquals),
+ Args<TypeExpr>([expr, _nullType]));
+ final narrowedNotNull = _makeNarrowNotNull(node, expr);
+ final int varIndex = _variablesInfo.varIndex[lhs.variable];
+ if (_variableCells[varIndex] == null) {
+ trueState[varIndex] = _nullType;
+ falseState[varIndex] = narrowedNotNull;
+ }
+ _variableValues = null;
+ return;
} else if (node is IsExpression && node.operand is VariableGet) {
// Handle 'x is T', where x is a variable.
final operand = node.operand as VariableGet;
@@ -1630,6 +1665,30 @@
return result;
}
+ @override
+ TypeExpr visitInstanceInvocation(InstanceInvocation node) {
+ final receiverNode = node.receiver;
+ final receiver = _visit(receiverNode);
+ final args = _visitArguments(receiver, node.arguments);
+ final target = node.interfaceTarget;
+ if (receiverNode is ConstantExpression && node.name.text == '[]') {
+ Constant constant = receiverNode.constant;
+ if (constant is ListConstant) {
+ return _handleIndexingIntoListConstant(constant);
+ }
+ }
+ assert(target is Procedure && !target.isGetter);
+ // TODO(alexmarkov): overloaded arithmetic operators
+ final result = _makeCall(
+ node,
+ (node.receiver is ThisExpression)
+ ? new VirtualSelector(target)
+ : new InterfaceSelector(target),
+ args);
+ _updateReceiverAfterCall(receiverNode, receiver, node.name);
+ return result;
+ }
+
TypeExpr _handleIndexingIntoListConstant(ListConstant list) {
final elementTypes = new Set<Type>();
for (var element in list.entries) {
@@ -1649,27 +1708,103 @@
}
@override
- TypeExpr visitPropertyGet(PropertyGet node) {
- var receiver = _visit(node.receiver);
- var args = new Args<TypeExpr>([receiver]);
+ TypeExpr visitDynamicInvocation(DynamicInvocation node) {
+ final receiverNode = node.receiver;
+ final receiver = _visit(receiverNode);
+ final args = _visitArguments(receiver, node.arguments);
+ final result =
+ _makeCall(node, new DynamicSelector(CallKind.Method, node.name), args);
+ _updateReceiverAfterCall(receiverNode, receiver, node.name);
+ return result;
+ }
+
+ @override
+ TypeExpr visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+ _visitArguments(null, node.arguments);
+ return _staticType(node);
+ }
+
+ @override
+ TypeExpr visitFunctionInvocation(FunctionInvocation node) {
+ final receiverNode = node.receiver;
+ final receiver = _visit(receiverNode);
+ _visitArguments(receiver, node.arguments);
+ final result = _staticType(node);
+ _updateReceiverAfterCall(receiverNode, receiver, Name('call'));
+ return result;
+ }
+
+ @override
+ TypeExpr visitEqualsCall(EqualsCall node) {
+ final left = _visit(node.left);
+ final right = _visit(node.right);
final target = node.interfaceTarget;
+ return _makeCall(
+ node,
+ (node.left is ThisExpression)
+ ? new VirtualSelector(target)
+ : new InterfaceSelector(target),
+ Args<TypeExpr>([left, right]));
+ }
+
+ @override
+ TypeExpr visitEqualsNull(EqualsNull node) {
+ final arg = _visit(node.expression);
+ _makeNarrowNotNull(node, arg);
+ _makeCall(node, DirectSelector(_environment.coreTypes.objectEquals),
+ Args<TypeExpr>([arg, _nullType]));
+ return _boolType;
+ }
+
+ TypeExpr _handlePropertyGet(
+ TreeNode node, Expression receiverNode, Member target, Name selector) {
+ var receiver = _visit(receiverNode);
+ var args = new Args<TypeExpr>([receiver]);
TypeExpr result;
if (target == null) {
result = _makeCall(
- node, new DynamicSelector(CallKind.PropertyGet, node.name), args);
+ node, new DynamicSelector(CallKind.PropertyGet, selector), args);
} else {
result = _makeCall(
node,
- (node.receiver is ThisExpression)
+ (receiverNode is ThisExpression)
? new VirtualSelector(target, callKind: CallKind.PropertyGet)
: new InterfaceSelector(target, callKind: CallKind.PropertyGet),
args);
}
- _updateReceiverAfterCall(node.receiver, receiver, node.name);
+ _updateReceiverAfterCall(receiverNode, receiver, selector);
return result;
}
@override
+ TypeExpr visitPropertyGet(PropertyGet node) {
+ return _handlePropertyGet(
+ node, node.receiver, node.interfaceTarget, node.name);
+ }
+
+ @override
+ TypeExpr visitInstanceGet(InstanceGet node) {
+ return _handlePropertyGet(
+ node, node.receiver, node.interfaceTarget, node.name);
+ }
+
+ @override
+ TypeExpr visitInstanceTearOff(InstanceTearOff node) {
+ return _handlePropertyGet(
+ node, node.receiver, node.interfaceTarget, node.name);
+ }
+
+ @override
+ TypeExpr visitFunctionTearOff(FunctionTearOff node) {
+ return _handlePropertyGet(node, node.receiver, null, Name('call'));
+ }
+
+ @override
+ TypeExpr visitDynamicGet(DynamicGet node) {
+ return _handlePropertyGet(node, node.receiver, null, node.name);
+ }
+
+ @override
TypeExpr visitPropertySet(PropertySet node) {
var receiver = _visit(node.receiver);
var value = _visit(node.value);
@@ -1693,6 +1828,35 @@
}
@override
+ TypeExpr visitInstanceSet(InstanceSet node) {
+ var receiver = _visit(node.receiver);
+ var value = _visit(node.value);
+ var args = new Args<TypeExpr>([receiver, value]);
+ final target = node.interfaceTarget;
+ assert((target is Field) || ((target is Procedure) && target.isSetter));
+ _makeCall(
+ node,
+ (node.receiver is ThisExpression)
+ ? new VirtualSelector(target, callKind: CallKind.PropertySet)
+ : new InterfaceSelector(target, callKind: CallKind.PropertySet),
+ args);
+ _updateReceiverAfterCall(node.receiver, receiver, node.name,
+ isSetter: true);
+ return value;
+ }
+
+ @override
+ TypeExpr visitDynamicSet(DynamicSet node) {
+ var receiver = _visit(node.receiver);
+ var value = _visit(node.value);
+ var args = new Args<TypeExpr>([receiver, value]);
+ _makeCall(node, new DynamicSelector(CallKind.PropertySet, node.name), args);
+ _updateReceiverAfterCall(node.receiver, receiver, node.name,
+ isSetter: true);
+ return value;
+ }
+
+ @override
TypeExpr visitSuperMethodInvocation(SuperMethodInvocation node) {
assert(kPartialMixinResolution);
assert(_receiver != null, "Should have receiver. Node: $node");
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 427af73..e7ac652 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -256,7 +256,13 @@
}
final bool markSkipCheck = !callSite.useCheckedEntry &&
- (node is MethodInvocation || node is PropertySet);
+ (node is MethodInvocation ||
+ node is InstanceInvocation ||
+ node is DynamicInvocation ||
+ node is EqualsCall ||
+ node is PropertySet ||
+ node is InstanceSet ||
+ node is DynamicSet);
bool markReceiverNotInt = false;
@@ -264,7 +270,8 @@
// No information is needed for static calls.
if (node is! StaticInvocation &&
node is! StaticSet &&
- node is! StaticGet) {
+ node is! StaticGet &&
+ node is! StaticTearOff) {
// The compiler uses another heuristic in addition to the call-site
// annotation: if the call-site is non-dynamic and the interface target does
// not exist in the parent chain of _Smi (int is used as an approxmiation
@@ -298,11 +305,17 @@
// Tell the table selector assigner about the callsite.
final Selector selector = callSite.selector;
if (selector is InterfaceSelector && !_callSiteUsesDirectCall(node)) {
- if (node is PropertyGet) {
+ if (node is PropertyGet ||
+ node is InstanceGet ||
+ node is InstanceTearOff) {
_tableSelectorAssigner.registerGetterCall(
selector.member, callSite.isNullableReceiver);
} else {
- assert(node is MethodInvocation || node is PropertySet);
+ assert(node is MethodInvocation ||
+ node is InstanceInvocation ||
+ node is EqualsCall ||
+ node is PropertySet ||
+ node is InstanceSet);
_tableSelectorAssigner.registerMethodOrSetterCall(
selector.member, callSite.isNullableReceiver);
}
@@ -428,18 +441,84 @@
}
@override
+ visitInstanceInvocation(InstanceInvocation node) {
+ _annotateCallSite(node, node.interfaceTarget);
+ super.visitInstanceInvocation(node);
+ }
+
+ @override
+ visitDynamicInvocation(DynamicInvocation node) {
+ _annotateCallSite(node, null);
+ super.visitDynamicInvocation(node);
+ }
+
+ @override
+ visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+ _annotateCallSite(node, null);
+ super.visitLocalFunctionInvocation(node);
+ }
+
+ @override
+ visitFunctionInvocation(FunctionInvocation node) {
+ _annotateCallSite(node, null);
+ super.visitFunctionInvocation(node);
+ }
+
+ @override
+ visitEqualsCall(EqualsCall node) {
+ _annotateCallSite(node, null);
+ super.visitEqualsCall(node);
+ }
+
+ @override
visitPropertyGet(PropertyGet node) {
_annotateCallSite(node, node.interfaceTarget);
super.visitPropertyGet(node);
}
@override
+ visitInstanceGet(InstanceGet node) {
+ _annotateCallSite(node, node.interfaceTarget);
+ super.visitInstanceGet(node);
+ }
+
+ @override
+ visitInstanceTearOff(InstanceTearOff node) {
+ _annotateCallSite(node, node.interfaceTarget);
+ super.visitInstanceTearOff(node);
+ }
+
+ @override
+ visitFunctionTearOff(FunctionTearOff node) {
+ _annotateCallSite(node, null);
+ super.visitFunctionTearOff(node);
+ }
+
+ @override
+ visitDynamicGet(DynamicGet node) {
+ _annotateCallSite(node, null);
+ super.visitDynamicGet(node);
+ }
+
+ @override
visitPropertySet(PropertySet node) {
_annotateCallSite(node, node.interfaceTarget);
super.visitPropertySet(node);
}
@override
+ visitInstanceSet(InstanceSet node) {
+ _annotateCallSite(node, node.interfaceTarget);
+ super.visitInstanceSet(node);
+ }
+
+ @override
+ visitDynamicSet(DynamicSet node) {
+ _annotateCallSite(node, null);
+ super.visitDynamicSet(node);
+ }
+
+ @override
visitSuperMethodInvocation(SuperMethodInvocation node) {
_annotateCallSite(node, node.interfaceTarget);
super.visitSuperMethodInvocation(node);
@@ -999,6 +1078,78 @@
}
@override
+ TreeNode visitInstanceInvocation(
+ InstanceInvocation node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall(
+ _flattenArguments(node.arguments, receiver: node.receiver));
+ }
+ node.interfaceTarget =
+ fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+ shaker.addUsedMember(node.interfaceTarget);
+ return node;
+ }
+
+ @override
+ TreeNode visitDynamicInvocation(
+ DynamicInvocation node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall(
+ _flattenArguments(node.arguments, receiver: node.receiver));
+ }
+ return node;
+ }
+
+ @override
+ TreeNode visitLocalFunctionInvocation(
+ LocalFunctionInvocation node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall(_flattenArguments(node.arguments));
+ }
+ return node;
+ }
+
+ @override
+ TreeNode visitFunctionInvocation(
+ FunctionInvocation node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall(
+ _flattenArguments(node.arguments, receiver: node.receiver));
+ }
+ return node;
+ }
+
+ @override
+ TreeNode visitEqualsCall(EqualsCall node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall([node.left, node.right]);
+ }
+ node.interfaceTarget =
+ fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+ shaker.addUsedMember(node.interfaceTarget);
+ return node;
+ }
+
+ @override
+ TreeNode visitEqualsNull(EqualsNull node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall([node.expression]);
+ }
+ final nullTest = _getNullTest(node);
+ if (nullTest.isAlwaysNull || nullTest.isAlwaysNotNull) {
+ return _evaluateArguments(
+ [node.expression], BoolLiteral(nullTest.isAlwaysNull));
+ }
+ return node;
+ }
+
+ @override
TreeNode visitPropertyGet(PropertyGet node, TreeNode removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
@@ -1014,6 +1165,54 @@
}
@override
+ TreeNode visitInstanceGet(InstanceGet node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall([node.receiver]);
+ } else {
+ node.interfaceTarget =
+ fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+ shaker.addUsedMember(node.interfaceTarget);
+ return node;
+ }
+ }
+
+ @override
+ TreeNode visitInstanceTearOff(
+ InstanceTearOff node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall([node.receiver]);
+ } else {
+ node.interfaceTarget =
+ fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+ shaker.addUsedMember(node.interfaceTarget);
+ return node;
+ }
+ }
+
+ @override
+ TreeNode visitDynamicGet(DynamicGet node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall([node.receiver]);
+ } else {
+ return node;
+ }
+ }
+
+ @override
+ TreeNode visitFunctionTearOff(
+ FunctionTearOff node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall([node.receiver]);
+ } else {
+ return node;
+ }
+ }
+
+ @override
TreeNode visitPropertySet(PropertySet node, TreeNode removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
@@ -1029,6 +1228,29 @@
}
@override
+ TreeNode visitInstanceSet(InstanceSet node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall([node.receiver, node.value]);
+ } else {
+ node.interfaceTarget = fieldMorpher
+ .adjustInstanceCallTarget(node.interfaceTarget, isSetter: true);
+ shaker.addUsedMember(node.interfaceTarget);
+ return node;
+ }
+ }
+
+ @override
+ TreeNode visitDynamicSet(DynamicSet node, TreeNode removalSentinel) {
+ node.transformOrRemoveChildren(this);
+ if (_isUnreachable(node)) {
+ return _makeUnreachableCall([node.receiver, node.value]);
+ } else {
+ return node;
+ }
+ }
+
+ @override
TreeNode visitSuperMethodInvocation(
SuperMethodInvocation node, TreeNode removalSentinel) {
node.transformOrRemoveChildren(this);