Files
sdk/pkg/vm/lib/transformations/cha_devirtualization.dart
T
Alexander Markov da61c326ed [VM/Kernel] Move devirtualization to pkg/vm, cleanup target-options
* The package:kernel/transformations/precompiler.dart is moved to
  package:vm and split into 2 libraries: metadata/direct_call and
  transformations/cha_devrtualization.

* Fasta 'target-options' command line argument and
  package:kernel/target/implementation_option.dart are cleaned up
  as they are no longer used.

Issue: https://github.com/dart-lang/sdk/issues/30480
Change-Id: I21a7b6bc62a036a9694e62a5dae890f6120d79ab
Reviewed-on: https://dart-review.googlesource.com/26360
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2017-12-06 18:49:33 +00:00

133 lines
4.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 vm.transformations.cha_devirtualization;
import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/class_hierarchy.dart' show ClosedWorldClassHierarchy;
import '../metadata/direct_call.dart';
/// Devirtualization of method invocations based on the class hierarchy
/// analysis. Assumes strong mode and closed world.
Program transformProgram(CoreTypes coreTypes, Program program) {
new _Devirtualization(coreTypes, program).visitProgram(program);
return program;
}
/// Resolves targets of instance method invocations, property getter
/// invocations and property setters invocations using strong mode
/// types / interface targets and closed-world class hierarchy analysis.
/// If direct target is determined, the invocation node is annotated
/// with direct call metadata.
class _Devirtualization extends RecursiveVisitor<Null> {
/// Toggles tracing (useful for debugging).
static const _trace = const bool.fromEnvironment('trace.devirtualization');
final ClosedWorldClassHierarchy _hierarchy;
final DirectCallMetadataRepository _metadata;
Set<Name> _objectMemberNames;
_Devirtualization(CoreTypes coreTypes, Program program)
: _hierarchy = new ClosedWorldClassHierarchy(program),
_metadata = new DirectCallMetadataRepository() {
_objectMemberNames = new Set<Name>.from(_hierarchy
.getInterfaceMembers(coreTypes.objectClass)
.map((Member m) => m.name));
program.addMetadataRepository(_metadata);
}
bool _isMethod(Member member) => (member is Procedure) && !member.isGetter;
bool _isFieldOrGetter(Member member) =>
(member is Field) || ((member is Procedure) && member.isGetter);
bool _isLegalTargetForMethodInvocation(Member target, Arguments arguments) {
final FunctionNode func = target.function;
final positionalArgs = arguments.positional.length;
if ((positionalArgs < func.requiredParameterCount) ||
(positionalArgs > func.positionalParameters.length)) {
return false;
}
if (arguments.named.isNotEmpty) {
final names = arguments.named.map((v) => v.name).toSet();
names.removeAll(func.namedParameters.map((v) => v.name));
if (names.isNotEmpty) {
return false;
}
}
return true;
}
_makeDirectCall(TreeNode node, Member target, Member singleTarget) {
if (_trace) {
print("[devirt] Resolving ${target} to ${singleTarget}");
}
_metadata.mapping[node] = new DirectCallMetadata(singleTarget, true);
}
@override
visitLibrary(Library node) {
if (_trace) {
String external = node.isExternal ? " (external)" : "";
print("[devirt] Processing library ${node.name}${external}");
}
super.visitLibrary(node);
}
@override
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
Member target = node.interfaceTarget;
if ((target != null) &&
_isMethod(target) &&
!_objectMemberNames.contains(target.name)) {
Member singleTarget =
_hierarchy.getSingleTargetForInterfaceInvocation(target);
// TODO(dartbug.com/30480): Convert _isLegalTargetForMethodInvocation()
// check into an assertion once front-end implements override checks.
if ((singleTarget != null) &&
_isMethod(singleTarget) &&
_isLegalTargetForMethodInvocation(singleTarget, node.arguments)) {
_makeDirectCall(node, target, singleTarget);
}
}
}
@override
visitPropertyGet(PropertyGet node) {
super.visitPropertyGet(node);
Member target = node.interfaceTarget;
if ((target != null) &&
_isFieldOrGetter(target) &&
!_objectMemberNames.contains(target.name)) {
Member singleTarget =
_hierarchy.getSingleTargetForInterfaceInvocation(target);
if ((singleTarget != null) && _isFieldOrGetter(singleTarget)) {
_makeDirectCall(node, target, singleTarget);
}
}
}
@override
visitPropertySet(PropertySet node) {
super.visitPropertySet(node);
Member target = node.interfaceTarget;
if (target != null) {
Member singleTarget = _hierarchy
.getSingleTargetForInterfaceInvocation(target, setter: true);
if (singleTarget != null) {
_makeDirectCall(node, target, singleTarget);
}
}
}
}