1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.dex.cf;
18
19import com.android.dx.rop.code.RopMethod;
20import com.android.dx.rop.code.TranslationAdvice;
21import com.android.dx.ssa.Optimizer;
22
23import java.io.BufferedReader;
24import java.io.FileReader;
25import java.io.IOException;
26import java.util.EnumSet;
27import java.util.HashSet;
28
29/**
30 * Settings for optimization of code.
31 */
32public class OptimizerOptions {
33    /**
34     * {@code null-ok;} hash set of class name + method names that
35     * should be optimized. {@code null} if this constraint was not
36     * specified on the command line
37     */
38    private static HashSet<String> optimizeList;
39
40    /**
41     * {@code null-ok;} hash set of class name + method names that should NOT
42     * be optimized.  null if this constraint was not specified on the
43     * command line
44     */
45    private static HashSet<String> dontOptimizeList;
46
47    /** true if the above lists have been loaded */
48    private static boolean optimizeListsLoaded;
49
50    /**
51     * This class is uninstantiable.
52     */
53    private OptimizerOptions() {
54        // This space intentionally left blank.
55    }
56
57    /**
58     * Loads the optimize/don't optimize lists from files.
59     *
60     * @param optimizeListFile Pathname
61     * @param dontOptimizeListFile Pathname
62     */
63    public static void loadOptimizeLists(String optimizeListFile,
64            String dontOptimizeListFile) {
65        if (optimizeListsLoaded) {
66            return;
67        }
68
69        if (optimizeListFile != null && dontOptimizeListFile != null) {
70            /*
71             * We shouldn't get this far. The condition should have
72             * been caught in the arg processor.
73             */
74            throw new RuntimeException("optimize and don't optimize lists "
75                    + " are mutually exclusive.");
76        }
77
78        if (optimizeListFile != null) {
79            optimizeList = loadStringsFromFile(optimizeListFile);
80        }
81
82        if (dontOptimizeListFile != null) {
83            dontOptimizeList = loadStringsFromFile(dontOptimizeListFile);
84        }
85
86        optimizeListsLoaded = true;
87    }
88
89    /**
90     * Loads a list of newline-separated strings into a new HashSet and returns
91     * the HashSet.
92     *
93     * @param filename filename to process
94     * @return set of all unique lines in the file
95     */
96    private static HashSet<String> loadStringsFromFile(String filename) {
97        HashSet<String> result = new HashSet<String>();
98
99        try {
100            FileReader fr = new FileReader(filename);
101            BufferedReader bfr = new BufferedReader(fr);
102
103            String line;
104
105            while (null != (line = bfr.readLine())) {
106                result.add(line);
107            }
108
109            fr.close();
110        } catch (IOException ex) {
111            // Let the exception percolate up as a RuntimeException.
112            throw new RuntimeException("Error with optimize list: " +
113                    filename, ex);
114        }
115
116        return result;
117    }
118
119    /**
120     * Compares the output of the optimizer run normally with a run skipping
121     * some optional steps. Results are printed to stderr.
122     *
123     * @param nonOptRmeth {@code non-null;} origional rop method
124     * @param paramSize {@code >= 0;} parameter size of method
125     * @param isStatic true if this method has no 'this' pointer argument.
126     * @param args {@code non-null;} translator arguments
127     * @param advice {@code non-null;} translation advice
128     * @param rmeth {@code non-null;} method with all optimization steps run.
129     */
130    public static void compareOptimizerStep(RopMethod nonOptRmeth,
131            int paramSize, boolean isStatic, CfOptions args,
132            TranslationAdvice advice, RopMethod rmeth) {
133        EnumSet<Optimizer.OptionalStep> steps;
134
135        steps = EnumSet.allOf(Optimizer.OptionalStep.class);
136
137        // This is the step to skip.
138        steps.remove(Optimizer.OptionalStep.CONST_COLLECTOR);
139
140        RopMethod skipRopMethod
141                = Optimizer.optimize(nonOptRmeth,
142                        paramSize, isStatic, args.localInfo, advice, steps);
143
144        int normalInsns
145                = rmeth.getBlocks().getEffectiveInstructionCount();
146        int skipInsns
147                = skipRopMethod.getBlocks().getEffectiveInstructionCount();
148
149        System.err.printf(
150                "optimize step regs:(%d/%d/%.2f%%)"
151                + " insns:(%d/%d/%.2f%%)\n",
152                rmeth.getBlocks().getRegCount(),
153                skipRopMethod.getBlocks().getRegCount(),
154                100.0 * ((skipRopMethod.getBlocks().getRegCount()
155                        - rmeth.getBlocks().getRegCount())
156                        / (float) skipRopMethod.getBlocks().getRegCount()),
157                normalInsns, skipInsns,
158                100.0 * ((skipInsns - normalInsns) / (float) skipInsns));
159    }
160
161    /**
162     * Checks whether the specified method should be optimized
163     *
164     * @param canonicalMethodName name of method being considered
165     * @return true if it should be optimized
166     */
167    public static boolean shouldOptimize(String canonicalMethodName) {
168        // Optimize only what's in the optimize list.
169        if (optimizeList != null) {
170            return optimizeList.contains(canonicalMethodName);
171        }
172
173        /*
174         * Or don't optimize what's listed here. (The two lists are
175         * mutually exclusive.
176         */
177
178        if (dontOptimizeList != null) {
179            return !dontOptimizeList.contains(canonicalMethodName);
180        }
181
182        // If neither list has been specified, then optimize everything.
183        return true;
184    }
185}
186