// 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'; import '../core_types.dart' show CoreTypes; import '../class_hierarchy.dart' show ClosedWorldClassHierarchy; /// Performs whole-program optimizations for Dart VM precompiler. /// Assumes strong mode and closed world. Program transformProgram(CoreTypes coreTypes, Program program) { new _Devirtualization(coreTypes, program).visitProgram(program); return program; } class DirectCallMetadata { final Member target; final bool checkReceiverForNull; DirectCallMetadata(this.target, this.checkReceiverForNull); } class DirectCallMetadataRepository extends MetadataRepository { @override final String tag = 'vm.direct-call.metadata'; @override final Map mapping = {}; @override void writeToBinary(DirectCallMetadata metadata, BinarySink sink) { sink.writeCanonicalNameReference(getCanonicalNameOfMember(metadata.target)); sink.writeByte(metadata.checkReceiverForNull ? 1 : 0); } @override DirectCallMetadata readFromBinary(BinarySource source) { var target = source.readCanonicalNameReference()?.getReference()?.asMember; if (target == null) { throw 'DirectCallMetadata should have a non-null target'; } var checkReceiverForNull = (source.readByte() != 0); return new DirectCallMetadata(target, checkReceiverForNull); } } /// 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 { /// Toggles tracing (useful for debugging). static const _trace = const bool.fromEnvironment('trace.devirtualization'); final ClosedWorldClassHierarchy _hierarchy; final DirectCallMetadataRepository _metadata; Set _objectMemberNames; _Devirtualization(CoreTypes coreTypes, Program program) : _hierarchy = new ClosedWorldClassHierarchy(program), _metadata = new DirectCallMetadataRepository() { _objectMemberNames = new Set.from(_hierarchy .getInterfaceMembers(coreTypes.objectClass) .map((Member m) => m.name)); program.addMetadataRepository(_metadata); } _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) && (target is! Field) && !_objectMemberNames.contains(target.name)) { Member singleTarget = _hierarchy.getSingleTargetForInterfaceInvocation(target); if ((singleTarget is Procedure) && !singleTarget.isGetter) { _makeDirectCall(node, target, singleTarget); } } return node; } @override visitPropertyGet(PropertyGet node) { super.visitPropertyGet(node); Member target = node.interfaceTarget; if ((target != null) && !_objectMemberNames.contains(target.name)) { Member singleTarget = _hierarchy.getSingleTargetForInterfaceInvocation(target); if (singleTarget != null) { _makeDirectCall(node, target, singleTarget); } } return node; } @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); } } return node; } }