/* * Copyright (C) 2007 The Android Open Source Project * * 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.android.dx.dex.cf; import com.android.dx.rop.code.RopMethod; import com.android.dx.rop.code.TranslationAdvice; import com.android.dx.ssa.Optimizer; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.EnumSet; import java.util.HashSet; /** * Settings for optimization of code. */ public class OptimizerOptions { /** * {@code null-ok;} hash set of class name + method names that * should be optimized. {@code null} if this constraint was not * specified on the command line */ private static HashSet<String> optimizeList; /** * {@code null-ok;} hash set of class name + method names that should NOT * be optimized. null if this constraint was not specified on the * command line */ private static HashSet<String> dontOptimizeList; /** true if the above lists have been loaded */ private static boolean optimizeListsLoaded; /** * This class is uninstantiable. */ private OptimizerOptions() { // This space intentionally left blank. } /** * Loads the optimize/don't optimize lists from files. * * @param optimizeListFile Pathname * @param dontOptimizeListFile Pathname */ public static void loadOptimizeLists(String optimizeListFile, String dontOptimizeListFile) { if (optimizeListsLoaded) { return; } if (optimizeListFile != null && dontOptimizeListFile != null) { /* * We shouldn't get this far. The condition should have * been caught in the arg processor. */ throw new RuntimeException("optimize and don't optimize lists " + " are mutually exclusive."); } if (optimizeListFile != null) { optimizeList = loadStringsFromFile(optimizeListFile); } if (dontOptimizeListFile != null) { dontOptimizeList = loadStringsFromFile(dontOptimizeListFile); } optimizeListsLoaded = true; } /** * Loads a list of newline-separated strings into a new HashSet and returns * the HashSet. * * @param filename filename to process * @return set of all unique lines in the file */ private static HashSet<String> loadStringsFromFile(String filename) { HashSet<String> result = new HashSet<String>(); try { FileReader fr = new FileReader(filename); BufferedReader bfr = new BufferedReader(fr); String line; while (null != (line = bfr.readLine())) { result.add(line); } fr.close(); } catch (IOException ex) { // Let the exception percolate up as a RuntimeException. throw new RuntimeException("Error with optimize list: " + filename, ex); } return result; } /** * Compares the output of the optimizer run normally with a run skipping * some optional steps. Results are printed to stderr. * * @param nonOptRmeth {@code non-null;} origional rop method * @param paramSize {@code >= 0;} parameter size of method * @param isStatic true if this method has no 'this' pointer argument. * @param args {@code non-null;} translator arguments * @param advice {@code non-null;} translation advice * @param rmeth {@code non-null;} method with all optimization steps run. */ public static void compareOptimizerStep(RopMethod nonOptRmeth, int paramSize, boolean isStatic, CfOptions args, TranslationAdvice advice, RopMethod rmeth) { EnumSet<Optimizer.OptionalStep> steps; steps = EnumSet.allOf(Optimizer.OptionalStep.class); // This is the step to skip. steps.remove(Optimizer.OptionalStep.CONST_COLLECTOR); RopMethod skipRopMethod = Optimizer.optimize(nonOptRmeth, paramSize, isStatic, args.localInfo, advice, steps); int normalInsns = rmeth.getBlocks().getEffectiveInstructionCount(); int skipInsns = skipRopMethod.getBlocks().getEffectiveInstructionCount(); System.err.printf( "optimize step regs:(%d/%d/%.2f%%)" + " insns:(%d/%d/%.2f%%)\n", rmeth.getBlocks().getRegCount(), skipRopMethod.getBlocks().getRegCount(), 100.0 * ((skipRopMethod.getBlocks().getRegCount() - rmeth.getBlocks().getRegCount()) / (float) skipRopMethod.getBlocks().getRegCount()), normalInsns, skipInsns, 100.0 * ((skipInsns - normalInsns) / (float) skipInsns)); } /** * Checks whether the specified method should be optimized * * @param canonicalMethodName name of method being considered * @return true if it should be optimized */ public static boolean shouldOptimize(String canonicalMethodName) { // Optimize only what's in the optimize list. if (optimizeList != null) { return optimizeList.contains(canonicalMethodName); } /* * Or don't optimize what's listed here. (The two lists are * mutually exclusive. */ if (dontOptimizeList != null) { return !dontOptimizeList.contains(canonicalMethodName); } // If neither list has been specified, then optimize everything. return true; } }