mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:07:57 +00:00
[vm/kernel] Refactor devirtualization to allow other implementations
This is a pure refactoring which extracts the base class for Devirtualization transformation. It is needed to add a new implementation of devirtualization later, in addition to the current CHA-based implementation. Change-Id: Ifbc6160150a842f5322cf5aea13a7c2180507c96 Reviewed-on: https://dart-review.googlesource.com/30620 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This commit is contained in:
parent
4ace8d42c0
commit
12086506f8
|
@ -17,7 +17,7 @@ import 'package:front_end/src/fasta/severity.dart' show Severity;
|
|||
import 'package:kernel/ast.dart' show Program;
|
||||
import 'package:kernel/core_types.dart' show CoreTypes;
|
||||
|
||||
import 'transformations/cha_devirtualization.dart' as chaDevirtualization
|
||||
import 'transformations/devirtualization.dart' as devirtualization
|
||||
show transformProgram;
|
||||
|
||||
/// Generates a kernel representation of the program whose main library is in
|
||||
|
@ -46,12 +46,10 @@ Future<Program> compileToKernel(Uri source, CompilerOptions options,
|
|||
}
|
||||
|
||||
_runGlobalTransformations(Program program, bool strongMode) {
|
||||
final coreTypes = new CoreTypes(program);
|
||||
|
||||
// TODO(alexmarkov): AOT-specific whole-program transformations.
|
||||
|
||||
if (strongMode) {
|
||||
chaDevirtualization.transformProgram(coreTypes, program);
|
||||
final coreTypes = new CoreTypes(program);
|
||||
|
||||
devirtualization.transformProgram(coreTypes, program);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,45 +6,46 @@ 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 'package:kernel/class_hierarchy.dart'
|
||||
show ClassHierarchy, 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);
|
||||
new CHADevirtualization(
|
||||
coreTypes, program, new ClosedWorldClassHierarchy(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> {
|
||||
/// Base class for implementing devirtualization of method invocations.
|
||||
/// Subclasses should implement particular devirtualization strategy in
|
||||
/// [getDirectCall] method. Once direct target is determined, the invocation
|
||||
/// node is annotated with direct call metadata.
|
||||
abstract 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
|
||||
Devirtualization(
|
||||
CoreTypes coreTypes, Program program, ClassHierarchy hierarchy)
|
||||
: _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 isMethod(Member member) => (member is Procedure) && !member.isGetter;
|
||||
|
||||
bool _isFieldOrGetter(Member member) =>
|
||||
bool isFieldOrGetter(Member member) =>
|
||||
(member is Field) || ((member is Procedure) && member.isGetter);
|
||||
|
||||
bool _isLegalTargetForMethodInvocation(Member target, Arguments arguments) {
|
||||
bool isLegalTargetForMethodInvocation(Member target, Arguments arguments) {
|
||||
final FunctionNode func = target.function;
|
||||
|
||||
final positionalArgs = arguments.positional.length;
|
||||
|
@ -64,11 +65,15 @@ class _Devirtualization extends RecursiveVisitor<Null> {
|
|||
return true;
|
||||
}
|
||||
|
||||
_makeDirectCall(TreeNode node, Member target, Member singleTarget) {
|
||||
DirectCallMetadata getDirectCall(TreeNode node, Member target,
|
||||
{bool setter = false});
|
||||
|
||||
makeDirectCall(TreeNode node, Member target, DirectCallMetadata directCall) {
|
||||
if (_trace) {
|
||||
print("[devirt] Resolving ${target} to ${singleTarget}");
|
||||
print("[devirt] Resolving ${target} to ${directCall.target}"
|
||||
" at ${node.location}");
|
||||
}
|
||||
_metadata.mapping[node] = new DirectCallMetadata(singleTarget, true);
|
||||
_metadata.mapping[node] = directCall;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -86,16 +91,15 @@ class _Devirtualization extends RecursiveVisitor<Null> {
|
|||
|
||||
Member target = node.interfaceTarget;
|
||||
if ((target != null) &&
|
||||
_isMethod(target) &&
|
||||
isMethod(target) &&
|
||||
!_objectMemberNames.contains(target.name)) {
|
||||
Member singleTarget =
|
||||
_hierarchy.getSingleTargetForInterfaceInvocation(target);
|
||||
DirectCallMetadata directCall = getDirectCall(node, 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);
|
||||
if ((directCall != null) &&
|
||||
isMethod(directCall.target) &&
|
||||
isLegalTargetForMethodInvocation(directCall.target, node.arguments)) {
|
||||
makeDirectCall(node, target, directCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,12 +110,11 @@ class _Devirtualization extends RecursiveVisitor<Null> {
|
|||
|
||||
Member target = node.interfaceTarget;
|
||||
if ((target != null) &&
|
||||
_isFieldOrGetter(target) &&
|
||||
isFieldOrGetter(target) &&
|
||||
!_objectMemberNames.contains(target.name)) {
|
||||
Member singleTarget =
|
||||
_hierarchy.getSingleTargetForInterfaceInvocation(target);
|
||||
if ((singleTarget != null) && _isFieldOrGetter(singleTarget)) {
|
||||
_makeDirectCall(node, target, singleTarget);
|
||||
DirectCallMetadata directCall = getDirectCall(node, target);
|
||||
if ((directCall != null) && isFieldOrGetter(directCall.target)) {
|
||||
makeDirectCall(node, target, directCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,11 +125,29 @@ class _Devirtualization extends RecursiveVisitor<Null> {
|
|||
|
||||
Member target = node.interfaceTarget;
|
||||
if (target != null) {
|
||||
Member singleTarget = _hierarchy
|
||||
.getSingleTargetForInterfaceInvocation(target, setter: true);
|
||||
if (singleTarget != null) {
|
||||
_makeDirectCall(node, target, singleTarget);
|
||||
DirectCallMetadata directCall = getDirectCall(node, target, setter: true);
|
||||
if (directCall != null) {
|
||||
makeDirectCall(node, target, directCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Devirtualization based on the closed-world class hierarchy analysis.
|
||||
class CHADevirtualization extends Devirtualization {
|
||||
final ClosedWorldClassHierarchy _hierarchy;
|
||||
|
||||
CHADevirtualization(CoreTypes coreTypes, Program program, this._hierarchy)
|
||||
: super(coreTypes, program, _hierarchy);
|
||||
|
||||
@override
|
||||
DirectCallMetadata getDirectCall(TreeNode node, Member target,
|
||||
{bool setter = false}) {
|
||||
Member singleTarget = _hierarchy
|
||||
.getSingleTargetForInterfaceInvocation(target, setter: setter);
|
||||
if (singleTarget == null) {
|
||||
return null;
|
||||
}
|
||||
return new DirectCallMetadata(singleTarget, true);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue