summaryrefslogtreecommitdiffstats
path: root/dx/src/com/android/dx/ssa/ConstCollector.java
diff options
context:
space:
mode:
Diffstat (limited to 'dx/src/com/android/dx/ssa/ConstCollector.java')
-rw-r--r--dx/src/com/android/dx/ssa/ConstCollector.java378
1 files changed, 0 insertions, 378 deletions
diff --git a/dx/src/com/android/dx/ssa/ConstCollector.java b/dx/src/com/android/dx/ssa/ConstCollector.java
deleted file mode 100644
index afdede7c2..000000000
--- a/dx/src/com/android/dx/ssa/ConstCollector.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright (C) 2008 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.ssa;
-
-import com.android.dx.rop.code.*;
-import com.android.dx.rop.type.TypeBearer;
-import com.android.dx.rop.type.StdTypeList;
-import com.android.dx.rop.type.Type;
-import com.android.dx.rop.cst.Constant;
-import com.android.dx.rop.cst.TypedConstant;
-import com.android.dx.rop.cst.CstString;
-
-import java.util.HashMap;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-
-/**
- * Collects constants that are used more than once at the top of the
- * method block. This increases register usage by about 5% but decreases
- * insn size by about 3%.
- */
-public class ConstCollector {
-
- /** Maximum constants to collect per method. Puts cap on reg use */
- private static final int MAX_COLLECTED_CONSTANTS = 5;
-
- /**
- * Also collect string consts, although they can throw exceptions.
- * This is off now because it just doesn't seem to gain a whole lot.
- * TODO if you turn this on, you must change SsaInsn.hasSideEffect()
- * to return false for const-string insns whose exceptions are not
- * caught in the current method.
- */
- private static boolean COLLECT_STRINGS = false;
-
- /**
- * If true, allow one local var to be involved with a collected const.
- * Turned off because it mostly just inserts more moves.
- */
- private static boolean COLLECT_ONE_LOCAL = false;
-
- /** method we're processing */
- private final SsaMethod ssaMeth;
-
- /**
- * Process a method.
- *
- * @param ssaMethod non-null; method to process
- */
- public static void process(SsaMethod ssaMethod) {
- ConstCollector dc;
-
- dc = new ConstCollector(ssaMethod);
-
- dc.run();
- }
-
- private ConstCollector(SsaMethod ssaMethod) {
- this.ssaMeth = ssaMethod;
- }
-
- /**
- * Applies the optimization.
- */
- private void run() {
- int regSz = ssaMeth.getRegCount();
-
- ArrayList<TypedConstant> constantList
- = getConstsSortedByCountUse();
-
- int toCollect = Math.min(constantList.size(), MAX_COLLECTED_CONSTANTS);
-
- SsaBasicBlock start = ssaMeth.getEntryBlock();
-
- // Constant to new register containing the constant
- HashMap<TypedConstant, RegisterSpec> newRegs
- = new HashMap<TypedConstant, RegisterSpec> (toCollect);
-
- for (int i = 0; i < toCollect; i++) {
- TypedConstant cst = constantList.get(i);
- RegisterSpec result
- = RegisterSpec.make(ssaMeth.makeNewSsaReg(), cst);
-
- Rop constRop = Rops.opConst(cst);
-
- if (constRop.getBranchingness() == Rop.BRANCH_NONE) {
- start.addInsnToHead(
- new PlainCstInsn(Rops.opConst(cst),
- SourcePosition.NO_INFO, result,
- RegisterSpecList.EMPTY, cst));
- } else {
- // We need two new basic blocks along with the new insn
- SsaBasicBlock entryBlock = ssaMeth.getEntryBlock();
- SsaBasicBlock successorBlock
- = entryBlock.getPrimarySuccessor();
-
- /*
- * Insert a block containing the const insn
- */
- SsaBasicBlock constBlock
- = entryBlock.insertNewSuccessor(successorBlock);
-
- constBlock.replaceLastInsn(
- new ThrowingCstInsn(constRop, SourcePosition.NO_INFO,
- RegisterSpecList.EMPTY,
- StdTypeList.EMPTY, cst));
-
- /*
- * Insert a block containing the move-result-pseudo insn
- */
-
- SsaBasicBlock resultBlock
- = constBlock.insertNewSuccessor(successorBlock);
-
- resultBlock.addInsnToHead(
- new PlainInsn(
- Rops.opMoveResultPseudo(result.getTypeBearer()),
- SourcePosition.NO_INFO,
- result, RegisterSpecList.EMPTY));
- }
-
- newRegs.put(cst, result);
- }
-
- updateConstUses(newRegs, regSz);
- }
-
- /**
- * Gets all of the collectable constant values used in this method,
- * sorted by most used first. Skips non-collectable consts, such as
- * non-string object constants
- *
- * @return non-null; list of constants in most-to-least used order
- */
- private ArrayList<TypedConstant> getConstsSortedByCountUse() {
- int regSz = ssaMeth.getRegCount();
-
- final HashMap<TypedConstant, Integer> countUses
- = new HashMap<TypedConstant, Integer>();
-
- // Each collected constant can be used by just one local
- // (used only if COLLECT_ONE_LOCAL is true)
- final HashSet<TypedConstant> usedByLocal
- = new HashSet<TypedConstant>();
-
- // Count how many times each const value is used
- for (int i = 0; i < regSz; i++) {
- SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
-
- if (insn == null) continue;
-
- RegisterSpec result = insn.getResult();
-
- TypeBearer typeBearer = insn.getResult().getTypeBearer();
-
- if (!typeBearer.isConstant()) continue;
-
- TypedConstant cst = (TypedConstant) typeBearer;
-
- if (insn.canThrow()) {
- /*
- * Don't move anything other than strings -- the risk
- * of changing where an exception is thrown is too high.
- */
- if (!(cst instanceof CstString) || !COLLECT_STRINGS) {
- continue;
- }
- /*
- * We can't move any throwable const whose throw will be caught,
- * so don't count them.
- */
- if (insn.getBlock().getSuccessors().cardinality() > 1) {
- continue;
- }
- }
-
- // TODO might be nice to try and figure out which local wins most
- // when collected
- if (ssaMeth.isRegALocal(result)) {
- if (!COLLECT_ONE_LOCAL) {
- continue;
- } else {
- if (usedByLocal.contains(cst)) {
- // Count one local usage only
- continue;
- } else {
- usedByLocal.add(cst);
- }
- }
- }
-
- Integer has = countUses.get(cst);
- if (has == null) {
- countUses.put(cst, 1);
- } else {
- countUses.put(cst, has + 1);
- }
- }
-
- // Collect constants that have been reused
- Iterator<TypedConstant> it = countUses.keySet().iterator();
- ArrayList<TypedConstant> constantList = new ArrayList<TypedConstant>();
- while (it.hasNext()) {
- TypedConstant cst = it.next();
-
- if (countUses.get(cst) > 1) {
- constantList.add(cst);
- }
- }
-
- // Sort by use, with most used at the beginning of the list
- Collections.sort(constantList, new Comparator<Constant>() {
- public int compare(Constant a, Constant b) {
- int ret;
- ret = countUses.get(b) - countUses.get(a);
-
- if (ret == 0) {
- /*
- * Provide sorting determinisim for constants with same
- * usage count.
- */
- ret = a.compareTo(b);
- }
-
- return ret;
- }
- public boolean equals (Object obj) {
- return obj == this;
- }
- });
- return constantList;
- }
-
- /**
- * Inserts mark-locals if necessary when changing a register. If
- * the definition of <code>origReg</code> is associated with a local
- * variable, then insert a mark-local for <code>newReg</code> just below
- * it. We expect the definition of <code>origReg</code> to ultimately
- * be removed by the dead code eliminator
- *
- * @param origReg non-null; original register
- * @param newReg non-null; new register that will replace
- * <code>origReg</code>
- */
- private void fixLocalAssignment(RegisterSpec origReg, RegisterSpec newReg) {
- for (SsaInsn use: ssaMeth.getUseListForRegister(origReg.getReg())) {
- RegisterSpec localAssignment = use.getLocalAssignment();
- if (localAssignment == null) {
- continue;
- }
-
- if (use.getResult() == null) {
- // this is a mark-local. it will be updated when all uses
- // are updated
- continue;
- }
-
- LocalItem local = localAssignment.getLocalItem();
-
- /*
- * un-associate original use
- */
- use.setResultLocal(null);
-
- /*
- * now add a mark-local to the new reg immediately after
- */
- newReg = newReg.withLocalItem(local);
-
- SsaInsn newInsn
- = SsaInsn.makeFromRop(
- new PlainInsn(Rops.opMarkLocal(newReg),
- SourcePosition.NO_INFO, null,
- RegisterSpecList.make(newReg)),
- use.getBlock());
-
- ArrayList<SsaInsn> insns = use.getBlock().getInsns();
-
- insns.add(insns.indexOf(use) + 1, newInsn);
- }
- }
-
- /**
- * Updates all uses of various consts to use the values in the newly
- * assigned registers.
- *
- * @param newRegs non-null; mapping between constant and new reg
- * @param origRegCount &gt;=0; original SSA reg count, not including
- * newly added constant regs
- */
- private void updateConstUses(HashMap<TypedConstant, RegisterSpec> newRegs,
- int origRegCount) {
-
- // Set of constants associated with a local variable
- // Used only if COLLECT_ONE_LOCAL is true
- final HashSet<TypedConstant> usedByLocal
- = new HashSet<TypedConstant>();
-
- final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
-
- for (int i = 0; i < origRegCount; i++) {
- SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
-
- if (insn == null) {
- continue;
- }
-
- final RegisterSpec origReg = insn.getResult();
- TypeBearer typeBearer = insn.getResult().getTypeBearer();
-
- if (!typeBearer.isConstant()) continue;
-
- TypedConstant cst = (TypedConstant) typeBearer;
- final RegisterSpec newReg = newRegs.get(cst);
-
- if (newReg == null) {
- continue;
- }
-
- if (ssaMeth.isRegALocal(origReg)) {
- if (!COLLECT_ONE_LOCAL) {
- continue;
- } else {
- // TODO if the same local gets the same cst multiple times,
- // it would be nice to reuse the register
- if (usedByLocal.contains(cst)) {
- continue;
- } else {
- usedByLocal.add(cst);
- fixLocalAssignment(origReg, newRegs.get(cst));
- }
- }
- }
-
- // Maps an original const register to the new collected register
- RegisterMapper mapper = new RegisterMapper() {
- @Override
- public int getNewRegisterCount() {
- return ssaMeth.getRegCount();
- }
-
- @Override
- public RegisterSpec map(RegisterSpec registerSpec) {
- if (registerSpec.getReg() == origReg.getReg()) {
- return newReg.withLocalItem(registerSpec.getLocalItem());
- }
-
- return registerSpec;
- }
- };
-
- for (SsaInsn use: useList[origReg.getReg()]) {
- if (use.canThrow()
- && use.getBlock().getSuccessors().cardinality() > 1) {
- continue;
- }
- use.mapSourceRegisters(mapper);
- }
- }
- }
-}