/* * 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()); } } }