/* * This file is part of JOP, the Java Optimized Processor * see <http://www.jopdesign.com/> * * Copyright (C) 2011, Stefan Hepp (stefan@stefant.org). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.jopdesign.jcopter; import com.jopdesign.common.AppInfo; import com.jopdesign.common.MethodInfo; import com.jopdesign.common.config.BooleanOption; import com.jopdesign.common.config.Config; import com.jopdesign.common.config.Config.BadConfigurationException; import com.jopdesign.common.config.Option; import com.jopdesign.common.config.OptionGroup; import com.jopdesign.common.config.StringOption; import org.apache.log4j.Logger; import java.util.Collections; import java.util.List; /** * This class contains all generic options for JCopter. * * Options of optimizations are defined in their respective classes and are added to the config * by the PhaseExecutor. * * @author Stefan Hepp (stefan@stefant.org) */ public class JCopterConfig { private static final BooleanOption ASSUME_REFLECTION = new BooleanOption("assume-reflection", "Assume that reflection is used. If not set, check the code for reflection code.", false); private static final BooleanOption ASSUME_DYNAMIC_CLASSLOADING = new BooleanOption("assume-dynloader", "Assume that classes can be loaded or replaced at runtime.", false); private static final StringOption OPTIMIZE = new StringOption("optimize", "can be one of: 's' (size), '1' (fast optimizations only), '2' (most optimizations), '3' (bring on the big guns)", 'O', "1"); private static final BooleanOption ALLOW_EXPERIMENTAL = new BooleanOption("experimental", "Enable experimental optimizations which are still in development", false); private static final StringOption MAX_CODE_SIZE = new StringOption("max-code-size", "maximum total code size, 'kb' or 'mb' can be used as suffix", true); private static final BooleanOption USE_WCA = new BooleanOption("use-wca", "Use the WCA tool to optimize for WCET", false); private static final StringOption WCA_TARGETS = // TODO change back when WCAInvoker supports more than one target method // new StringOption("wca-targets", "comma separated list of target-methods if the WCA is used (main class is used if the classname is omitted)", "measure"); new StringOption("wca-target", "target-method if the WCA is used (main class is used if the classname is omitted)", "measure"); private static final Option[] optionList = { OPTIMIZE, ALLOW_EXPERIMENTAL, MAX_CODE_SIZE, ASSUME_REFLECTION, ASSUME_DYNAMIC_CLASSLOADING, USE_WCA, WCA_TARGETS }; public static void registerOptions(OptionGroup options) { options.addOptions(JCopterConfig.optionList); } private static final Logger logger = Logger.getLogger(JCopter.LOG_ROOT+".JCopterConfig"); private final OptionGroup options; private byte optimizeLevel; private int maxCodesize; private List<MethodInfo> wcaTargets; public JCopterConfig(OptionGroup options) throws BadConfigurationException { this.options = options; loadOptions(); } private void loadOptions() throws BadConfigurationException { if ("s".equals(options.getOption(OPTIMIZE))) { optimizeLevel = 0; } else if ("1".equals(options.getOption(OPTIMIZE))) { optimizeLevel = 1; } else if ("2".equals(options.getOption(OPTIMIZE))) { optimizeLevel = 2; } else if ("3".equals(options.getOption(OPTIMIZE))) { optimizeLevel = 3; } else { throw new BadConfigurationException("Invalid optimization level '"+options.getOption(OPTIMIZE)+"'"); } String max = options.getOption(MAX_CODE_SIZE); if (max != null) { max = max.toLowerCase(); if (max.endsWith("kb")) { maxCodesize = Integer.parseInt(max.substring(0,max.length()-2)) * 1024; } else if (max.endsWith("mb")) { maxCodesize = Integer.parseInt(max.substring(0,max.length()-2)) * 1024 * 1024; } else { maxCodesize = Integer.parseInt(max); } } else { // TODO if we do not have max size: should we use some heuristics to limit codesize? } } /** * Check the options, check if the assumptions on the code hold. * @throws BadConfigurationException if the WCA_TARGETS option is not set correctly */ public void initialize() throws BadConfigurationException { // need to do this here because main method class is not available on load if (useWCA()) { wcaTargets = Config.parseMethodList(options.getOption(WCA_TARGETS)); } else if (options.isSet(WCA_TARGETS)) { try { wcaTargets = Config.parseMethodList(options.getOption(WCA_TARGETS)); } catch (BadConfigurationException ignored) { logger.warn("WCA target method is set to "+options.getOption(WCA_TARGETS)+" but does not exist, ignored since WCA is not used."); } } else { try { wcaTargets = Config.parseMethodList(options.getOption(WCA_TARGETS)); } catch (BadConfigurationException ignored) { logger.debug("Default WCA target method not found, ignored since WCA is not used."); } } // TODO implement reflection check, implement incomplete code check } public AppInfo getAppInfo() { return AppInfo.getSingleton(); } public Config getConfig() { return options.getConfig(); } public boolean useWCA() { return options.getOption(USE_WCA); } public List<MethodInfo> getWCATargets() { return wcaTargets == null ? Collections.<MethodInfo>emptyList() : wcaTargets; } /** * @return true if we need to assume that reflection is used in the code. */ public boolean doAssumeReflection() { return options.getOption(ASSUME_REFLECTION); } public boolean doAssumeDynamicClassLoader() { return options.getOption(ASSUME_DYNAMIC_CLASSLOADING); } /** * @return true if we need to assume that the class hierarchy is not fully known */ public boolean doAssumeIncompleteAppInfo() { // TODO Reflection may lead to loading of additional code not referenced explicitly in ConstantPool // on the other hand, it might not.. We could distinguish this using additional options. return getAppInfo().doIgnoreMissingClasses() || doAssumeReflection() || doAssumeDynamicClassLoader(); } public int getCallstringLength() { return (int) getConfig().getOption(Config.CALLSTRING_LENGTH).longValue(); } public int getMaxCodesize() { return maxCodesize; } /** * Includes optimizations which are more expensive, excludes optimization which increase size. * @return true if we should only perform optimizations which reduce the total codesize. */ public boolean doOptimizeCodesizeOnly() { return optimizeLevel == 0; } /** * Includes optimizations which may increase size, excludes optimizations which are more expensive. * @return true if we only want fast optimizations. */ public boolean doOptimizeFastOnly() { return optimizeLevel == 1; } /** * Includes all optimizations which are more expensive, may increase size. Excludes optimizations which may take * a long time. * @return true if we want most optimizations to execute. */ public boolean doOptimizeNormal() { return optimizeLevel >= 2; } /** * Includes everything. * @return true if we want to try really hard to optimize, even if it may take a long time. */ public boolean doOptimizeHard() { return optimizeLevel >= 3; } public boolean doAllowExperimental() { return options.getOption(ALLOW_EXPERIMENTAL); } }