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;
22import java.io.BufferedReader;
23import java.io.FileReader;
24import java.io.IOException;
25import java.util.EnumSet;
26import java.util.HashSet;
27
28/**
29 * Settings for optimization of code.
30 */
31public class OptimizerOptions {
32    /**
33     * {@code null-ok;} hash set of class name + method names that
34     * should be optimized. {@code null} if this constraint was not
35     * specified on the command line
36     */
37    private HashSet<String> optimizeList;
38
39    /**
40     * {@code null-ok;} hash set of class name + method names that should NOT
41     * be optimized.  null if this constraint was not specified on the
42     * command line
43     */
44    private HashSet<String> dontOptimizeList;
45
46    /** true if the above lists have been loaded */
47    private boolean optimizeListsLoaded;
48
49
50    /**
51     * Loads the optimize/don't optimize lists from files.
52     *
53     * @param optimizeListFile Pathname
54     * @param dontOptimizeListFile Pathname
55     */
56    public void loadOptimizeLists(String optimizeListFile,
57            String dontOptimizeListFile) {
58        if (optimizeListsLoaded) {
59            return;
60        }
61
62        if (optimizeListFile != null && dontOptimizeListFile != null) {
63            /*
64             * We shouldn't get this far. The condition should have
65             * been caught in the arg processor.
66             */
67            throw new RuntimeException("optimize and don't optimize lists "
68                    + " are mutually exclusive.");
69        }
70
71        if (optimizeListFile != null) {
72            optimizeList = loadStringsFromFile(optimizeListFile);
73        }
74
75        if (dontOptimizeListFile != null) {
76            dontOptimizeList = loadStringsFromFile(dontOptimizeListFile);
77        }
78
79        optimizeListsLoaded = true;
80    }
81
82    /**
83     * Loads a list of newline-separated strings into a new HashSet and returns
84     * the HashSet.
85     *
86     * @param filename filename to process
87     * @return set of all unique lines in the file
88     */
89    private static HashSet<String> loadStringsFromFile(String filename) {
90        HashSet<String> result = new HashSet<String>();
91
92        try {
93            FileReader fr = new FileReader(filename);
94            BufferedReader bfr = new BufferedReader(fr);
95
96            String line;
97
98            while (null != (line = bfr.readLine())) {
99                result.add(line);
100            }
101
102            fr.close();
103        } catch (IOException ex) {
104            // Let the exception percolate up as a RuntimeException.
105            throw new RuntimeException("Error with optimize list: " +
106                    filename, ex);
107        }
108
109        return result;
110    }
111
112    /**
113     * Compares the output of the optimizer run normally with a run skipping
114     * some optional steps. Results are printed to stderr.
115     *
116     * @param nonOptRmeth {@code non-null;} origional rop method
117     * @param paramSize {@code >= 0;} parameter size of method
118     * @param isStatic true if this method has no 'this' pointer argument.
119     * @param args {@code non-null;} translator arguments
120     * @param advice {@code non-null;} translation advice
121     * @param rmeth {@code non-null;} method with all optimization steps run.
122     */
123    public void compareOptimizerStep(RopMethod nonOptRmeth,
124            int paramSize, boolean isStatic, CfOptions args,
125            TranslationAdvice advice, RopMethod rmeth) {
126        EnumSet<Optimizer.OptionalStep> steps;
127
128        steps = EnumSet.allOf(Optimizer.OptionalStep.class);
129
130        // This is the step to skip.
131        steps.remove(Optimizer.OptionalStep.CONST_COLLECTOR);
132
133        RopMethod skipRopMethod
134                = Optimizer.optimize(nonOptRmeth,
135                        paramSize, isStatic, args.localInfo, advice, steps);
136
137        int normalInsns
138                = rmeth.getBlocks().getEffectiveInstructionCount();
139        int skipInsns
140                = skipRopMethod.getBlocks().getEffectiveInstructionCount();
141
142        System.err.printf(
143                "optimize step regs:(%d/%d/%.2f%%)"
144                + " insns:(%d/%d/%.2f%%)\n",
145                rmeth.getBlocks().getRegCount(),
146                skipRopMethod.getBlocks().getRegCount(),
147                100.0 * ((skipRopMethod.getBlocks().getRegCount()
148                        - rmeth.getBlocks().getRegCount())
149                        / (float) skipRopMethod.getBlocks().getRegCount()),
150                normalInsns, skipInsns,
151                100.0 * ((skipInsns - normalInsns) / (float) skipInsns));
152    }
153
154    /**
155     * Checks whether the specified method should be optimized
156     *
157     * @param canonicalMethodName name of method being considered
158     * @return true if it should be optimized
159     */
160    public boolean shouldOptimize(String canonicalMethodName) {
161        // Optimize only what's in the optimize list.
162        if (optimizeList != null) {
163            return optimizeList.contains(canonicalMethodName);
164        }
165
166        /*
167         * Or don't optimize what's listed here. (The two lists are
168         * mutually exclusive.
169         */
170
171        if (dontOptimizeList != null) {
172            return !dontOptimizeList.contains(canonicalMethodName);
173        }
174
175        // If neither list has been specified, then optimize everything.
176        return true;
177    }
178}
179