Files
sdk/pkg/kernel/lib/transformations/precompiler.dart
T
Alexander Markov 8a368a1a4c [Kernel, VM/AOT] Avoid DirectMethodInvocations to getters or fields
This CL changes devirtualization to detect corner case of a method
invocation which is resolved to a getter or a field. This kind of
invocation should call getter first, and then call 'call()' method on
the result of the getter, passing the rest of the arguments.

For simplicity, devirtualization of such method invocations is avoided.

Issue: https://github.com/dart-lang/sdk/issues/30480
Change-Id: Ibe6321931cbb5527a26b139c5f1ee9773a253629
Reviewed-on: https://dart-review.googlesource.com/5902
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2017-09-15 16:15:12 +00:00

116 lines
3.5 KiB
Dart

// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library kernel.transformations.precompiler;
import '../ast.dart'
show
DirectMethodInvocation,
DirectPropertyGet,
DirectPropertySet,
Field,
Library,
Member,
MethodInvocation,
Procedure,
Program,
PropertyGet,
PropertySet,
TreeNode;
import '../core_types.dart' show CoreTypes;
import '../class_hierarchy.dart' show ClosedWorldClassHierarchy;
import '../visitor.dart' show Transformer;
/// Performs whole-program transformations for Dart VM precompiler.
/// Assumes strong mode and closed world.
Program transformProgram(CoreTypes coreTypes, Program program) {
new _DevirtualizationTransformer(program).visitProgram(program);
return program;
}
/// Transforms instance method invocations into direct using strong mode
/// types / interface targets and closed-world class hierarchy analysis.
class _DevirtualizationTransformer extends Transformer {
/// Toggles tracing (useful for debugging).
static const _trace = const bool.fromEnvironment('trace.devirtualization');
ClosedWorldClassHierarchy _hierarchy;
_DevirtualizationTransformer(Program program)
: _hierarchy = new ClosedWorldClassHierarchy(program) {}
@override
TreeNode visitLibrary(Library node) {
if (_trace) {
String external = node.isExternal ? " (external)" : "";
print("[devirt] Processing library ${node.name}${external}");
}
return super.visitLibrary(node);
}
@override
TreeNode visitMethodInvocation(MethodInvocation node) {
node = super.visitMethodInvocation(node);
Member target = node.interfaceTarget;
if ((target != null) && (target is! Field)) {
Member singleTarget =
_hierarchy.getSingleTargetForInterfaceInvocation(target);
if ((singleTarget is Procedure) && !singleTarget.isGetter) {
if (_trace) {
print("[devirt] Replacing ${target} with ${singleTarget}");
}
// TODO(dartbug.com/30480): add annotation to check for null
return new DirectMethodInvocation(
node.receiver, singleTarget, node.arguments);
}
}
return node;
}
@override
TreeNode visitPropertyGet(PropertyGet node) {
node = super.visitPropertyGet(node);
Member target = node.interfaceTarget;
if (target != null) {
Member singleTarget =
_hierarchy.getSingleTargetForInterfaceInvocation(target);
if (singleTarget != null) {
if (_trace) {
print("[devirt] Replacing ${target} with ${singleTarget}");
}
// TODO(dartbug.com/30480): add annotation to check for null
return new DirectPropertyGet(node.receiver, singleTarget);
}
}
return node;
}
@override
TreeNode visitPropertySet(PropertySet node) {
node = super.visitPropertySet(node);
Member target = node.interfaceTarget;
if (target != null) {
Member singleTarget = _hierarchy
.getSingleTargetForInterfaceInvocation(target, setter: true);
if (singleTarget != null) {
if (_trace) {
print("[devirt] Replacing ${target} with ${singleTarget}");
}
// TODO(dartbug.com/30480): add annotation to check for null
return new DirectPropertySet(node.receiver, singleTarget, node.value);
}
}
return node;
}
}