blob: a5db2e7c136919a077d2ef7c0c319eb8bf7ccb00 [file] [log] [blame]
// 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.no_dynamic_invocations_annotator;
import 'package:kernel/ast.dart';
import '../metadata/procedure_attributes.dart';
/// Assumes strong mode and closed world. If a procedure can not be riched
/// via dynamic invocation from anywhere then annotates it with appropriate
/// [ProcedureAttributeMetadata] annotation.
Program transformProgram(Program program) {
new NoDynamicInvocationsAnnotator(program).visitProgram(program);
return program;
}
enum Action { get, set, invoke }
class Selector {
final Action action;
final Name target;
Selector(this.action, this.target);
bool operator ==(other) {
return other is Selector &&
other.action == this.action &&
other.target == this.target;
}
int get hashCode => (action.index * 31) ^ target.hashCode;
@override
String toString() {
switch (action) {
case Action.get:
return 'get:${target}';
case Action.set:
return 'set:${target}';
case Action.invoke:
return '${target}';
}
return '?';
}
}
class NoDynamicInvocationsAnnotator extends RecursiveVisitor<Null> {
final Set<Selector> _dynamicSelectors;
final ProcedureAttributesMetadataRepository _metadata;
NoDynamicInvocationsAnnotator(Program program)
: _dynamicSelectors = DynamicSelectorsCollector.collect(program),
_metadata = new ProcedureAttributesMetadataRepository() {
program.addMetadataRepository(_metadata);
}
@override
visitProcedure(Procedure node) {
if (node.isStatic || node.name.name == 'call') {
return;
}
Selector selector;
if (node.kind == ProcedureKind.Method) {
selector = new Selector(Action.invoke, node.name);
} else if (node.kind == ProcedureKind.Setter) {
selector = new Selector(Action.set, node.name);
} else {
return;
}
if (!_dynamicSelectors.contains(selector)) {
_metadata.mapping[node] =
const ProcedureAttributesMetadata.noDynamicInvocations();
}
}
}
class DynamicSelectorsCollector extends RecursiveVisitor<Null> {
final Set<Selector> dynamicSelectors = new Set<Selector>();
static Set<Selector> collect(Program program) {
final v = new DynamicSelectorsCollector();
v.visitProgram(program);
return v.dynamicSelectors;
}
@override
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
if (node.dispatchCategory == DispatchCategory.dynamicDispatch) {
dynamicSelectors.add(new Selector(Action.invoke, node.name));
}
}
@override
visitPropertyGet(PropertyGet node) {
super.visitPropertyGet(node);
if (node.dispatchCategory == DispatchCategory.dynamicDispatch) {
dynamicSelectors.add(new Selector(Action.get, node.name));
}
}
@override
visitPropertySet(PropertySet node) {
super.visitPropertySet(node);
if (node.dispatchCategory == DispatchCategory.dynamicDispatch) {
dynamicSelectors.add(new Selector(Action.set, node.name));
}
}
}