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