blob: 43a29e757a80cda69ea4dd43abbeef213304d4b7 [file] [log] [blame]
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.jjs.impl;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JNode;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.thirdparty.guava.common.collect.HashMultiset;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.collect.Multiset;
import com.google.gwt.thirdparty.guava.common.collect.Sets;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* Maintains dependence and modification information for AST optimizers.
* <p>
* Is updated incrementally.
*/
public class FullOptimizerContext implements OptimizerContext {
private int optimizationStep = -1;
private CallGraph callGraph = new CallGraph();
private FieldReferencesGraph fieldReferencesGraph = new FieldReferencesGraph();
/**
* The deleted sub call graph and added sub call graph at each step.
*/
private List<CallGraph> deletedSubCallGraphs = Lists.newArrayList();
private List<CallGraph> addedSubCallGraphs = Lists.newArrayList();
// TODO(leafwang): add other dependencies here
/**
* A mapping from methods to the numbers of the most recent step in which they were modified.
*/
private Multiset<JMethod> modificationStepByMethod = HashMultiset.create();
/**
* A list of modified methods in each step.
*/
private List<Set<JMethod>> methodsByModificationStep = Lists.newArrayList();
/**
* A mapping from methods to the numbers of the most recent step in which they were modified.
*/
private Multiset<JField> modificationStepByField = HashMultiset.create();
/**
* A list of modified fields in each step.
*/
private List<Set<JField>> fieldsByModificationStep = Lists.newArrayList();
/**
* A mapping from optimizers to their last modification step.
*/
private Multiset<String> lastStepForOptimizer = HashMultiset.create();
public FullOptimizerContext(JProgram program) {
incOptimizationStep();
initializeModifications(program);
buildCallGraph(program);
buildFieldReferencesGraph(program);
incOptimizationStep();
}
@Override
public Set<JMethod> getCallees(Collection<JMethod> callerMethods) {
return callGraph.getCallees(callerMethods);
}
@Override
public Set<JMethod> getCallers(Collection<JMethod> calleeMethods) {
return callGraph.getCallers(calleeMethods);
}
@Override
public int getLastStepFor(String optimizerName) {
return lastStepForOptimizer.count(optimizerName);
}
@Override
public Set<JMethod> getMethodsByReferencedFields(Collection<JField> fields) {
return fieldReferencesGraph.getReferencingMethodsForFields(fields);
}
@Override
public Set<JField> getModifiedFieldsSince(int stepSince) {
Set<JField> result = Sets.newLinkedHashSet();
for (int i = stepSince; i < optimizationStep; i++) {
result.addAll(fieldsByModificationStep.get(i));
}
return result;
}
@Override
public Set<JMethod> getModifiedMethodsSince(int stepSince) {
Set<JMethod> result = Sets.newLinkedHashSet();
for (int i = stepSince; i < optimizationStep; i++) {
result.addAll(methodsByModificationStep.get(i));
}
return result;
}
@Override
public int getOptimizationStep() {
return optimizationStep;
}
@Override
public Set<JField> getReferencedFieldsByMethods(Collection<JMethod> methods) {
return fieldReferencesGraph.getReferencedFieldsByMethods(methods);
}
@Override
public Set<JMethod> getRemovedCalleeMethodsSince(int stepSince) {
Set<JMethod> removedCalleeMethods = Sets.newLinkedHashSet();
for (int i = stepSince; i < optimizationStep; i++) {
removedCalleeMethods.addAll(deletedSubCallGraphs.get(i).getAllCallees());
}
return removedCalleeMethods;
}
@Override
public void incOptimizationStep() {
methodsByModificationStep.add(new LinkedHashSet<JMethod>());
fieldsByModificationStep.add(new LinkedHashSet<JField>());
deletedSubCallGraphs.add(new CallGraph());
addedSubCallGraphs.add(new CallGraph());
optimizationStep++;
}
@Override
public void markModified(JField modifiedField) {
fieldsByModificationStep.get(modificationStepByField.count(modifiedField)).remove(
modifiedField);
fieldsByModificationStep.get(optimizationStep).add(modifiedField);
modificationStepByField.setCount(modifiedField, optimizationStep);
// TODO(leafwang): update related dependence information here.
}
@Override
public void markModified(JMethod modifiedMethod) {
methodsByModificationStep.get(modificationStepByMethod.count(modifiedMethod)).remove(
modifiedMethod);
methodsByModificationStep.get(optimizationStep).add(modifiedMethod);
modificationStepByMethod.setCount(modifiedMethod, optimizationStep);
callGraph.updateCallGraphOfMethod(modifiedMethod, deletedSubCallGraphs.get(optimizationStep),
addedSubCallGraphs.get(optimizationStep));
fieldReferencesGraph.updateFieldReferencesOfMethod(modifiedMethod);
}
@Override
public void remove(JField field) {
fieldsByModificationStep.get(modificationStepByField.count(field)).remove(field);
modificationStepByField.remove(field);
fieldReferencesGraph.removeField(field);
}
@Override
public void remove(JMethod method) {
methodsByModificationStep.get(modificationStepByMethod.count(method)).remove(method);
modificationStepByMethod.remove(method);
Set<JMethod> calleeMethods = callGraph.removeCallerMethod(method);
deletedSubCallGraphs.get(optimizationStep).addCallerMethod(method,
Sets.difference(calleeMethods, callGraph.getCallees(Collections.singleton(method))));
addedSubCallGraphs.get(optimizationStep).addCallerMethod(method,
Sets.difference(callGraph.getCallees(Collections.singleton(method)), calleeMethods));
fieldReferencesGraph.removeMethod(method);
}
@Override
public void removeFields(Collection<JField> fields) {
for (JField field : fields) {
remove(field);
}
}
@Override
public void removeMethods(Collection<JMethod> methods) {
for (JMethod method : methods) {
remove(method);
}
}
@Override
public void setLastStepFor(String optimizerName, int step) {
lastStepForOptimizer.setCount(optimizerName, step);
}
@Override
public void syncDeletedSubCallGraphsSince(int step, Collection<JMethod> prunedMethods) {
for (int i = step; i < optimizationStep; i++) {
for (JMethod prunedMethod : prunedMethods) {
deletedSubCallGraphs.get(i).removeCallerMethod(prunedMethod);
deletedSubCallGraphs.get(i).removeCalleeMethod(prunedMethod);
}
}
}
@Override
public void traverse(JVisitor visitor, Set<? extends JNode> nodes) {
assert (nodes != null);
for (JNode node : nodes) {
visitor.accept(node);
}
}
private void buildCallGraph(JProgram program) {
callGraph.buildCallGraph(program);
}
private void buildFieldReferencesGraph(JProgram program) {
fieldReferencesGraph.buildFieldReferencesGraph(program);
}
private void initializeModifications(JProgram program) {
assert optimizationStep == 0;
for (JDeclaredType type : program.getModuleDeclaredTypes()) {
fieldsByModificationStep.get(0).addAll(type.getFields());
methodsByModificationStep.get(0).addAll(type.getMethods());
}
}
}