summaryrefslogtreecommitdiffstats
path: root/dx
diff options
context:
space:
mode:
authormikaelpeltier <mikaelpeltier@google.com>2014-04-24 17:43:53 +0200
committermikaelpeltier <mikaelpeltier@google.com>2014-04-25 08:37:23 +0200
commit4a7e57f27f0d03a7ed18befc6e9c82aebd9daeda (patch)
treef759cb11e706b1a5688c0074c293b9b4fb60af41 /dx
parentacfd4fe200a29e3dc939ad9b51f717905b74ad33 (diff)
downloadtoolchain_jack-4a7e57f27f0d03a7ed18befc6e9c82aebd9daeda.zip
toolchain_jack-4a7e57f27f0d03a7ed18befc6e9c82aebd9daeda.tar.gz
toolchain_jack-4a7e57f27f0d03a7ed18befc6e9c82aebd9daeda.tar.bz2
Remove escape analysis since it is always disabled
Change-Id: Ic4ee669aea4c361f72f991ed199fef4c6afb0df1
Diffstat (limited to 'dx')
-rw-r--r--dx/src/com/android/jack/dx/ssa/EscapeAnalysis.java817
-rw-r--r--dx/src/com/android/jack/dx/ssa/Optimizer.java12
2 files changed, 1 insertions, 828 deletions
diff --git a/dx/src/com/android/jack/dx/ssa/EscapeAnalysis.java b/dx/src/com/android/jack/dx/ssa/EscapeAnalysis.java
deleted file mode 100644
index 6021941..0000000
--- a/dx/src/com/android/jack/dx/ssa/EscapeAnalysis.java
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * Copyright (C) 2010 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.jack.dx.ssa;
-
-import com.android.jack.dx.rop.code.Exceptions;
-import com.android.jack.dx.rop.code.FillArrayDataInsn;
-import com.android.jack.dx.rop.code.Insn;
-import com.android.jack.dx.rop.code.PlainCstInsn;
-import com.android.jack.dx.rop.code.PlainInsn;
-import com.android.jack.dx.rop.code.RegOps;
-import com.android.jack.dx.rop.code.RegisterSpec;
-import com.android.jack.dx.rop.code.RegisterSpecList;
-import com.android.jack.dx.rop.code.Rop;
-import com.android.jack.dx.rop.code.Rops;
-import com.android.jack.dx.rop.code.ThrowingCstInsn;
-import com.android.jack.dx.rop.code.ThrowingInsn;
-import com.android.jack.dx.rop.cst.Constant;
-import com.android.jack.dx.rop.cst.CstLiteralBits;
-import com.android.jack.dx.rop.cst.CstMethodRef;
-import com.android.jack.dx.rop.cst.CstNat;
-import com.android.jack.dx.rop.cst.CstString;
-import com.android.jack.dx.rop.cst.CstType;
-import com.android.jack.dx.rop.cst.TypedConstant;
-import com.android.jack.dx.rop.cst.Zeroes;
-import com.android.jack.dx.rop.type.StdTypeList;
-import com.android.jack.dx.rop.type.Type;
-import com.android.jack.dx.rop.type.TypeBearer;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashSet;
-import java.util.List;
-
-/**
- * Simple intraprocedural escape analysis. Finds new arrays that don't escape
- * the method they are created in and replaces the array values with registers.
- */
-public class EscapeAnalysis {
- /**
- * Struct used to generate and maintain escape analysis results.
- */
- static class EscapeSet {
- /** set containing all registers related to an object */
- BitSet regSet;
- /** escape state of the object */
- EscapeState escape;
- /** list of objects that are put into this object */
- ArrayList<EscapeSet> childSets;
- /** list of objects that this object is put into */
- ArrayList<EscapeSet> parentSets;
- /** flag to indicate this object is a scalar replaceable array */
- boolean replaceableArray;
-
- /**
- * Constructs an instance of an EscapeSet
- *
- * @param reg the SSA register that defines the object
- * @param size the number of registers in the method
- * @param escState the lattice value to initially set this to
- */
- EscapeSet(int reg, int size, EscapeState escState) {
- regSet = new BitSet(size);
- regSet.set(reg);
- escape = escState;
- childSets = new ArrayList<EscapeSet>();
- parentSets = new ArrayList<EscapeSet>();
- replaceableArray = false;
- }
- }
-
- /**
- * Lattice values used to indicate escape state for an object. Analysis can
- * only raise escape state values, not lower them.
- *
- * TOP - Used for objects that haven't been analyzed yet
- * NONE - Object does not escape, and is eligible for scalar replacement.
- * METHOD - Object remains local to method, but can't be scalar replaced.
- * INTER - Object is passed between methods. (treated as globally escaping
- * since this is an intraprocedural analysis)
- * GLOBAL - Object escapes globally.
- */
- public enum EscapeState {
- TOP, NONE, METHOD, INTER, GLOBAL
- }
-
- /** method we're processing */
- private SsaMethod ssaMeth;
- /** ssaMeth.getRegCount() */
- private int regCount;
- /** Lattice values for each object register group */
- private ArrayList<EscapeSet> latticeValues;
-
- /**
- * Constructs an instance.
- *
- * @param ssaMeth method to process
- */
- private EscapeAnalysis(SsaMethod ssaMeth) {
- this.ssaMeth = ssaMeth;
- this.regCount = ssaMeth.getRegCount();
- this.latticeValues = new ArrayList<EscapeSet>();
- }
-
- /**
- * Finds the index in the lattice for a particular register.
- * Returns the size of the lattice if the register wasn't found.
- *
- * @param reg {@code non-null;} register being looked up
- * @return index of the register or size of the lattice if it wasn't found.
- */
- private int findSetIndex(RegisterSpec reg) {
- int i;
- for (i = 0; i < latticeValues.size(); i++) {
- EscapeSet e = latticeValues.get(i);
- if (e.regSet.get(reg.getReg())) {
- return i;
- }
- }
- return i;
- }
-
- /**
- * Finds the corresponding instruction for a given move result
- *
- * @param moveInsn {@code non-null;} a move result instruction
- * @return {@code non-null;} the instruction that produces the result for
- * the move
- */
- private SsaInsn getInsnForMove(SsaInsn moveInsn) {
- int pred = moveInsn.getBlock().getPredecessors().nextSetBit(0);
- ArrayList<SsaInsn> predInsns = ssaMeth.getBlocks().get(pred).getInsns();
- return predInsns.get(predInsns.size() - 1);
- }
-
- /**
- * Finds the corresponding move result for a given instruction
- *
- * @param insn {@code non-null;} an instruction that must always be
- * followed by a move result
- * @return {@code non-null;} the move result for the given instruction
- */
- private SsaInsn getMoveForInsn(SsaInsn insn) {
- int succ = insn.getBlock().getSuccessors().nextSetBit(0);
- ArrayList<SsaInsn> succInsns = ssaMeth.getBlocks().get(succ).getInsns();
- return succInsns.get(0);
- }
-
- /**
- * Creates a link in the lattice between two EscapeSets due to a put
- * instruction. The object being put is the child and the object being put
- * into is the parent. A child set must always have an escape state at
- * least as high as its parent.
- *
- * @param parentSet {@code non-null;} the EscapeSet for the object being put
- * into
- * @param childSet {@code non-null;} the EscapeSet for the object being put
- */
- private void addEdge(EscapeSet parentSet, EscapeSet childSet) {
- if (!childSet.parentSets.contains(parentSet)) {
- childSet.parentSets.add(parentSet);
- }
- if (!parentSet.childSets.contains(childSet)) {
- parentSet.childSets.add(childSet);
- }
- }
-
- /**
- * Merges all links in the lattice among two EscapeSets. On return, the
- * newNode will have its old links as well as all links from the oldNode.
- * The oldNode has all its links removed.
- *
- * @param newNode {@code non-null;} the EscapeSet to merge all links into
- * @param oldNode {@code non-null;} the EscapeSet to remove all links from
- */
- private void replaceNode(EscapeSet newNode, EscapeSet oldNode) {
- for (EscapeSet e : oldNode.parentSets) {
- e.childSets.remove(oldNode);
- e.childSets.add(newNode);
- newNode.parentSets.add(e);
- }
- for (EscapeSet e : oldNode.childSets) {
- e.parentSets.remove(oldNode);
- e.parentSets.add(newNode);
- newNode.childSets.add(e);
- }
- }
-
- /**
- * Performs escape analysis on a method. Finds scalar replaceable arrays and
- * replaces them with equivalent registers.
- *
- * @param ssaMethod {@code non-null;} method to process
- */
- public static void process(SsaMethod ssaMethod) {
- new EscapeAnalysis(ssaMethod).run();
- }
-
- /**
- * Process a single instruction, looking for new objects resulting from
- * move result or move param.
- *
- * @param insn {@code non-null;} instruction to process
- */
- private void processInsn(SsaInsn insn) {
- int op = insn.getOpcode().getOpcode();
- RegisterSpec result = insn.getResult();
- EscapeSet escSet;
-
- // Identify new objects
- if (op == RegOps.MOVE_RESULT_PSEUDO
- && result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
- // Handle objects generated through move_result_pseudo
- escSet = processMoveResultPseudoInsn(insn);
- processRegister(result, escSet);
- } else if (op == RegOps.MOVE_PARAM && result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
- // Track method arguments that are objects
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
- latticeValues.add(escSet);
- processRegister(result, escSet);
- } else if (op == RegOps.MOVE_RESULT
- && result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
- // Track method return values that are objects
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
- latticeValues.add(escSet);
- processRegister(result, escSet);
- }
- }
-
- /**
- * Determine the origin of a move result pseudo instruction that generates
- * an object. Creates a new EscapeSet for the new object accordingly.
- *
- * @param insn {@code non-null;} move result pseudo instruction to process
- * @return {@code non-null;} an EscapeSet for the object referred to by the
- * move result pseudo instruction
- */
- private EscapeSet processMoveResultPseudoInsn(SsaInsn insn) {
- RegisterSpec result = insn.getResult();
- SsaInsn prevSsaInsn = getInsnForMove(insn);
- int prevOpcode = prevSsaInsn.getOpcode().getOpcode();
- EscapeSet escSet;
- RegisterSpec prevSource;
-
- switch (prevOpcode) {
- // New instance / Constant
- case RegOps.NEW_INSTANCE:
- case RegOps.CONST:
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
- break;
- // New array
- case RegOps.NEW_ARRAY:
- case RegOps.FILLED_NEW_ARRAY:
- prevSource = prevSsaInsn.getSources().get(0);
- if (prevSource.getTypeBearer().isConstant()) {
- // New fixed array
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
- escSet.replaceableArray = true;
- } else {
- // New variable array
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.GLOBAL);
- }
- break;
- // Loading a static object
- case RegOps.GET_STATIC:
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.GLOBAL);
- break;
- // Type cast / load an object from a field or array
- case RegOps.CHECK_CAST:
- case RegOps.GET_FIELD:
- case RegOps.AGET:
- prevSource = prevSsaInsn.getSources().get(0);
- int setIndex = findSetIndex(prevSource);
-
- // Set should already exist, try to find it
- if (setIndex != latticeValues.size()) {
- escSet = latticeValues.get(setIndex);
- escSet.regSet.set(result.getReg());
- return escSet;
- }
-
- // Set not found, must be either null or unknown
- if (prevSource.getType() == Type.KNOWN_NULL) {
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
- } else {
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.GLOBAL);
- }
- break;
- default:
- return null;
- }
-
- // Add the newly created escSet to the lattice and return it
- latticeValues.add(escSet);
- return escSet;
- }
-
- /**
- * Iterate through all the uses of a new object.
- *
- * @param result {@code non-null;} register where new object is stored
- * @param escSet {@code non-null;} EscapeSet for the new object
- */
- private void processRegister(RegisterSpec result, EscapeSet escSet) {
- ArrayList<RegisterSpec> regWorklist = new ArrayList<RegisterSpec>();
- regWorklist.add(result);
-
- // Go through the worklist
- while (!regWorklist.isEmpty()) {
- int listSize = regWorklist.size() - 1;
- RegisterSpec def = regWorklist.remove(listSize);
- List<SsaInsn> useList = ssaMeth.getUseListForRegister(def.getReg());
-
- // Handle all the uses of this register
- for (SsaInsn use : useList) {
- Rop useOpcode = use.getOpcode();
-
- if (useOpcode == null) {
- // Handle phis
- processPhiUse(use, escSet, regWorklist);
- } else {
- // Handle other opcodes
- processUse(def, use, escSet, regWorklist);
- }
- }
- }
- }
-
- /**
- * Handles phi uses of new objects. Will merge together the sources of a phi
- * into a single EscapeSet. Adds the result of the phi to the worklist so
- * its uses can be followed.
- *
- * @param use {@code non-null;} phi use being processed
- * @param escSet {@code non-null;} EscapeSet for the object
- * @param regWorklist {@code non-null;} worklist of instructions left to
- * process for this object
- */
- private void processPhiUse(SsaInsn use, EscapeSet escSet, ArrayList<RegisterSpec> regWorklist) {
- int setIndex = findSetIndex(use.getResult());
- if (setIndex != latticeValues.size()) {
- // Check if result is in a set already
- EscapeSet mergeSet = latticeValues.get(setIndex);
- if (mergeSet != escSet) {
- // If it is, merge the sets and states, then delete the copy
- escSet.replaceableArray = false;
- escSet.regSet.or(mergeSet.regSet);
- if (escSet.escape.compareTo(mergeSet.escape) < 0) {
- escSet.escape = mergeSet.escape;
- }
- replaceNode(escSet, mergeSet);
- latticeValues.remove(setIndex);
- }
- } else {
- // If no set is found, add it to this escSet and the worklist
- escSet.regSet.set(use.getResult().getReg());
- regWorklist.add(use.getResult());
- }
- }
-
- /**
- * Handles non-phi uses of new objects. Checks to see how instruction is
- * used and updates the escape state accordingly.
- *
- * @param def {@code non-null;} register holding definition of new object
- * @param use {@code non-null;} use of object being processed
- * @param escSet {@code non-null;} EscapeSet for the object
- * @param regWorklist {@code non-null;} worklist of instructions left to
- * process for this object
- */
- private void processUse(RegisterSpec def, SsaInsn use, EscapeSet escSet,
- ArrayList<RegisterSpec> regWorklist) {
- int useOpcode = use.getOpcode().getOpcode();
- switch (useOpcode) {
- case RegOps.MOVE:
- // Follow uses of the move by adding it to the worklist
- escSet.regSet.set(use.getResult().getReg());
- regWorklist.add(use.getResult());
- break;
- case RegOps.IF_EQ:
- case RegOps.IF_NE:
- case RegOps.CHECK_CAST:
- // Compared objects can't be replaced, so promote if necessary
- if (escSet.escape.compareTo(EscapeState.METHOD) < 0) {
- escSet.escape = EscapeState.METHOD;
- }
- break;
- case RegOps.APUT:
- // For array puts, check for a constant array index
- RegisterSpec putIndex = use.getSources().get(2);
- if (!putIndex.getTypeBearer().isConstant()) {
- // If not constant, array can't be replaced
- escSet.replaceableArray = false;
- }
- // Intentional fallthrough
- case RegOps.PUT_FIELD:
- // Skip non-object puts
- RegisterSpec putValue = use.getSources().get(0);
- if (putValue.getTypeBearer().getBasicType() != Type.BT_OBJECT) {
- break;
- }
- escSet.replaceableArray = false;
-
- // Raise 1st object's escape state to 2nd if 2nd is higher
- RegisterSpecList sources = use.getSources();
- if (sources.get(0).getReg() == def.getReg()) {
- int setIndex = findSetIndex(sources.get(1));
- if (setIndex != latticeValues.size()) {
- EscapeSet parentSet = latticeValues.get(setIndex);
- addEdge(parentSet, escSet);
- if (escSet.escape.compareTo(parentSet.escape) < 0) {
- escSet.escape = parentSet.escape;
- }
- }
- } else {
- int setIndex = findSetIndex(sources.get(0));
- if (setIndex != latticeValues.size()) {
- EscapeSet childSet = latticeValues.get(setIndex);
- addEdge(escSet, childSet);
- if (childSet.escape.compareTo(escSet.escape) < 0) {
- childSet.escape = escSet.escape;
- }
- }
- }
- break;
- case RegOps.AGET:
- // For array gets, check for a constant array index
- RegisterSpec getIndex = use.getSources().get(1);
- if (!getIndex.getTypeBearer().isConstant()) {
- // If not constant, array can't be replaced
- escSet.replaceableArray = false;
- }
- break;
- case RegOps.PUT_STATIC:
- // Static puts cause an object to escape globally
- escSet.escape = EscapeState.GLOBAL;
- break;
- case RegOps.INVOKE_STATIC:
- case RegOps.INVOKE_VIRTUAL:
- case RegOps.INVOKE_SUPER:
- case RegOps.INVOKE_DIRECT:
- case RegOps.INVOKE_INTERFACE:
- case RegOps.RETURN:
- case RegOps.THROW:
- // These operations cause an object to escape interprocedurally
- escSet.escape = EscapeState.INTER;
- break;
- default:
- break;
- }
- }
-
- /**
- * Performs scalar replacement on all eligible arrays.
- */
- private void scalarReplacement() {
- // Iterate through lattice, looking for non-escaping replaceable arrays
- for (EscapeSet escSet : latticeValues) {
- if (!escSet.replaceableArray || escSet.escape != EscapeState.NONE) {
- continue;
- }
-
- // Get the instructions for the definition and move of the array
- int e = escSet.regSet.nextSetBit(0);
- SsaInsn def = ssaMeth.getDefinitionForRegister(e);
- SsaInsn prev = getInsnForMove(def);
-
- // Create a map for the new registers that will be created
- TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
- int length = ((CstLiteralBits) lengthReg).getIntBits();
- ArrayList<RegisterSpec> newRegs = new ArrayList<RegisterSpec>(length);
- HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
-
- // Replace the definition of the array with registers
- replaceDef(def, prev, length, newRegs);
-
- // Mark definition instructions for deletion
- deletedInsns.add(prev);
- deletedInsns.add(def);
-
- // Go through all uses of the array
- List<SsaInsn> useList = ssaMeth.getUseListForRegister(e);
- for (SsaInsn use : useList) {
- // Replace the use with scalars and then mark it for deletion
- replaceUse(use, prev, newRegs, deletedInsns);
- deletedInsns.add(use);
- }
-
- // Delete all marked instructions
- ssaMeth.deleteInsns(deletedInsns);
- ssaMeth.onInsnsChanged();
-
- // Convert the method back to SSA form
- SsaConverter.updateSsaMethod(ssaMeth, regCount);
-
- // Propagate and remove extra moves added by scalar replacement
- movePropagate();
- }
- }
-
- /**
- * Replaces the instructions that define an array with equivalent registers.
- * For each entry in the array, a register is created, initialized to zero.
- * A mapping between this register and the corresponding array index is
- * added.
- *
- * @param def {@code non-null;} move result instruction for array
- * @param prev {@code non-null;} instruction for instantiating new array
- * @param length size of the new array
- * @param newRegs {@code non-null;} mapping of array indices to new
- * registers to be populated
- */
- private void replaceDef(SsaInsn def, SsaInsn prev, int length, ArrayList<RegisterSpec> newRegs) {
- Type resultType = def.getResult().getType();
-
- // Create new zeroed out registers for each element in the array
- for (int i = 0; i < length; i++) {
- Constant newZero = Zeroes.zeroFor(resultType.getComponentType());
- TypedConstant typedZero = (TypedConstant) newZero;
- RegisterSpec newReg = RegisterSpec.make(ssaMeth.makeNewSsaReg(), typedZero);
- newRegs.add(newReg);
- insertPlainInsnBefore(def, RegisterSpecList.EMPTY, newReg, RegOps.CONST, newZero);
- }
- }
-
- /**
- * Replaces the use for a scalar replaceable array. Gets and puts become
- * move instructions, and array lengths and fills are handled. Can also
- * identify ArrayIndexOutOfBounds exceptions and throw them if detected.
- *
- * @param use {@code non-null;} move result instruction for array
- * @param prev {@code non-null;} instruction for instantiating new array
- * @param newRegs {@code non-null;} mapping of array indices to new
- * registers
- * @param deletedInsns {@code non-null;} set of instructions marked for
- * deletion
- */
- private void replaceUse(SsaInsn use, SsaInsn prev, ArrayList<RegisterSpec> newRegs,
- HashSet<SsaInsn> deletedInsns) {
- int index;
- int length = newRegs.size();
- SsaInsn next;
- RegisterSpecList sources;
- RegisterSpec source, result;
- CstLiteralBits indexReg;
-
- switch (use.getOpcode().getOpcode()) {
- case RegOps.AGET:
- // Replace array gets with moves
- next = getMoveForInsn(use);
- sources = use.getSources();
- indexReg = ((CstLiteralBits) sources.get(1).getTypeBearer());
- index = indexReg.getIntBits();
- if (index < length) {
- source = newRegs.get(index);
- result = source.withReg(next.getResult().getReg());
- insertPlainInsnBefore(next, RegisterSpecList.make(source), result, RegOps.MOVE, null);
- } else {
- // Throw an exception if the index is out of bounds
- insertExceptionThrow(next, sources.get(1), deletedInsns);
- deletedInsns.add(next.getBlock().getInsns().get(2));
- }
- deletedInsns.add(next);
- break;
- case RegOps.APUT:
- // Replace array puts with moves
- sources = use.getSources();
- indexReg = ((CstLiteralBits) sources.get(2).getTypeBearer());
- index = indexReg.getIntBits();
- if (index < length) {
- source = sources.get(0);
- result = source.withReg(newRegs.get(index).getReg());
- insertPlainInsnBefore(use, RegisterSpecList.make(source), result, RegOps.MOVE, null);
- // Update the newReg entry to mark value as unknown now
- newRegs.set(index, result.withSimpleType());
- } else {
- // Throw an exception if the index is out of bounds
- insertExceptionThrow(use, sources.get(2), deletedInsns);
- }
- break;
- case RegOps.ARRAY_LENGTH:
- // Replace array lengths with const instructions
- TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
- //CstInteger lengthReg = CstInteger.make(length);
- next = getMoveForInsn(use);
- insertPlainInsnBefore(next, RegisterSpecList.EMPTY, next.getResult(), RegOps.CONST,
- (Constant) lengthReg);
- deletedInsns.add(next);
- break;
- case RegOps.MARK_LOCAL:
- // Remove mark local instructions
- break;
- case RegOps.FILL_ARRAY_DATA:
- // Create const instructions for each fill value
- Insn ropUse = use.getOriginalRopInsn();
- FillArrayDataInsn fill = (FillArrayDataInsn) ropUse;
- ArrayList<Constant> constList = fill.getInitValues();
- for (int i = 0; i < length; i++) {
- RegisterSpec newFill =
- RegisterSpec.make(newRegs.get(i).getReg(), (TypeBearer) constList.get(i));
- insertPlainInsnBefore(use, RegisterSpecList.EMPTY, newFill, RegOps.CONST,
- constList.get(i));
- // Update the newRegs to hold the new const value
- newRegs.set(i, newFill);
- }
- break;
- default:
- }
- }
-
- /**
- * Identifies extra moves added by scalar replacement and propagates the
- * source of the move to any users of the result.
- */
- private void movePropagate() {
- for (int i = 0; i < ssaMeth.getRegCount(); i++) {
- SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
-
- // Look for move instructions only
- if (insn == null || insn.getOpcode() == null || insn.getOpcode().getOpcode() != RegOps.MOVE) {
- continue;
- }
-
- final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
- final RegisterSpec source = insn.getSources().get(0);
- final RegisterSpec result = insn.getResult();
-
- // Ignore moves that weren't added due to scalar replacement
- if (source.getReg() < regCount && result.getReg() < regCount) {
- continue;
- }
-
- // Create a mapping from source to result
- RegisterMapper mapper = new RegisterMapper() {
- @Override
- public int getNewRegisterCount() {
- return ssaMeth.getRegCount();
- }
-
- @Override
- public RegisterSpec map(RegisterSpec registerSpec) {
- if (registerSpec.getReg() == result.getReg()) {
- return source;
- }
-
- return registerSpec;
- }
- };
-
- // Modify all uses of the move to use the source of the move instead
- for (SsaInsn use : useList[result.getReg()]) {
- use.mapSourceRegisters(mapper);
- }
- }
- }
-
- /**
- * Runs escape analysis and scalar replacement of arrays.
- */
- private void run() {
- ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() {
- @Override
- public void visitBlock(SsaBasicBlock block, SsaBasicBlock unused) {
- block.forEachInsn(new SsaInsn.Visitor() {
- @Override
- public void visitMoveInsn(NormalSsaInsn insn) {
- // do nothing
- }
-
- @Override
- public void visitPhiInsn(PhiInsn insn) {
- // do nothing
- }
-
- @Override
- public void visitNonMoveInsn(NormalSsaInsn insn) {
- processInsn(insn);
- }
- });
- }
- });
-
- // Go through lattice and promote fieldSets as necessary
- for (EscapeSet e : latticeValues) {
- if (e.escape != EscapeState.NONE) {
- for (EscapeSet field : e.childSets) {
- if (e.escape.compareTo(field.escape) > 0) {
- field.escape = e.escape;
- }
- }
- }
- }
-
- // Perform scalar replacement for arrays
- scalarReplacement();
- }
-
- /**
- * Replaces instructions that trigger an ArrayIndexOutofBounds exception
- * with an actual throw of the exception.
- *
- * @param insn {@code non-null;} instruction causing the exception
- * @param index {@code non-null;} index value that is out of bounds
- * @param deletedInsns {@code non-null;} set of instructions marked for
- * deletion
- */
- private void insertExceptionThrow(SsaInsn insn, RegisterSpec index,
- HashSet<SsaInsn> deletedInsns) {
- // Create a new ArrayIndexOutOfBoundsException
- CstType exception = new CstType(Exceptions.TYPE_ArrayIndexOutOfBoundsException);
- insertThrowingInsnBefore(insn, RegisterSpecList.EMPTY, null, RegOps.NEW_INSTANCE, exception);
-
- // Add a successor block with a move result pseudo for the exception
- SsaBasicBlock currBlock = insn.getBlock();
- SsaBasicBlock newBlock = currBlock.insertNewSuccessor(currBlock.getPrimarySuccessor());
- SsaInsn newInsn = newBlock.getInsns().get(0);
- RegisterSpec newReg = RegisterSpec.make(ssaMeth.makeNewSsaReg(), exception);
- insertPlainInsnBefore(newInsn, RegisterSpecList.EMPTY, newReg, RegOps.MOVE_RESULT_PSEUDO, null);
-
- // Add another successor block to initialize the exception
- SsaBasicBlock newBlock2 = newBlock.insertNewSuccessor(newBlock.getPrimarySuccessor());
- SsaInsn newInsn2 = newBlock2.getInsns().get(0);
- CstNat newNat = new CstNat(new CstString("<init>"), new CstString("(I)V"));
- CstMethodRef newRef = new CstMethodRef(exception, newNat);
- insertThrowingInsnBefore(newInsn2, RegisterSpecList.make(newReg, index), null,
- RegOps.INVOKE_DIRECT, newRef);
- deletedInsns.add(newInsn2);
-
- // Add another successor block to throw the new exception
- SsaBasicBlock newBlock3 = newBlock2.insertNewSuccessor(newBlock2.getPrimarySuccessor());
- SsaInsn newInsn3 = newBlock3.getInsns().get(0);
- insertThrowingInsnBefore(newInsn3, RegisterSpecList.make(newReg), null, RegOps.THROW, null);
- newBlock3.replaceSuccessor(newBlock3.getPrimarySuccessorIndex(),
- ssaMeth.getExitBlock().getIndex());
- deletedInsns.add(newInsn3);
- }
-
- /**
- * Inserts a new PlainInsn before the given instruction.
- * TODO(dx team): move this somewhere more appropriate
- *
- * @param insn {@code non-null;} instruction to insert before
- * @param newSources {@code non-null;} sources of new instruction
- * @param newResult {@code non-null;} result of new instruction
- * @param newOpcode opcode of new instruction
- * @param cst {@code null-ok;} constant for new instruction, if any
- */
- private void insertPlainInsnBefore(SsaInsn insn, RegisterSpecList newSources,
- RegisterSpec newResult, int newOpcode, Constant cst) {
-
- Insn originalRopInsn = insn.getOriginalRopInsn();
- Rop newRop;
- if (newOpcode == RegOps.MOVE_RESULT_PSEUDO) {
- newRop = Rops.opMoveResultPseudo(newResult.getType());
- } else {
- newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
- }
-
- Insn newRopInsn;
- if (cst == null) {
- newRopInsn = new PlainInsn(newRop, originalRopInsn.getPosition(), newResult, newSources);
- } else {
- newRopInsn =
- new PlainCstInsn(newRop, originalRopInsn.getPosition(), newResult, newSources, cst);
- }
-
- NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
- List<SsaInsn> insns = insn.getBlock().getInsns();
-
- insns.add(insns.lastIndexOf(insn), newInsn);
- ssaMeth.onInsnAdded(newInsn);
- }
-
- /**
- * Inserts a new ThrowingInsn before the given instruction.
- * TODO(dx team): move this somewhere more appropriate
- *
- * @param insn {@code non-null;} instruction to insert before
- * @param newSources {@code non-null;} sources of new instruction
- * @param newResult {@code non-null;} result of new instruction
- * @param newOpcode opcode of new instruction
- * @param cst {@code null-ok;} constant for new instruction, if any
- */
- private void insertThrowingInsnBefore(SsaInsn insn, RegisterSpecList newSources,
- RegisterSpec newResult, int newOpcode, Constant cst) {
-
- Insn origRopInsn = insn.getOriginalRopInsn();
- Rop newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
- Insn newRopInsn;
- if (cst == null) {
- newRopInsn =
- new ThrowingInsn(newRop, origRopInsn.getPosition(), newSources, StdTypeList.EMPTY);
- } else {
- newRopInsn = new ThrowingCstInsn(newRop, origRopInsn.getPosition(), newSources,
- StdTypeList.EMPTY, cst);
- }
-
- NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
- List<SsaInsn> insns = insn.getBlock().getInsns();
-
- insns.add(insns.lastIndexOf(insn), newInsn);
- ssaMeth.onInsnAdded(newInsn);
- }
-}
diff --git a/dx/src/com/android/jack/dx/ssa/Optimizer.java b/dx/src/com/android/jack/dx/ssa/Optimizer.java
index 42c6d28..5e00e2e 100644
--- a/dx/src/com/android/jack/dx/ssa/Optimizer.java
+++ b/dx/src/com/android/jack/dx/ssa/Optimizer.java
@@ -34,7 +34,7 @@ public class Optimizer {
/** optional optimizer steps */
public enum OptionalStep {
- SCCP, LITERAL_UPGRADE, CONST_COLLECTOR, ESCAPE_ANALYSIS
+ SCCP, LITERAL_UPGRADE, CONST_COLLECTOR
}
/**
@@ -164,16 +164,6 @@ public class Optimizer {
needsDeadCodeRemover = false;
}
- /*
- * ESCAPE_ANALYSIS impacts debuggability, so left off by default
- */
- steps.remove(OptionalStep.ESCAPE_ANALYSIS);
- if (steps.contains(OptionalStep.ESCAPE_ANALYSIS)) {
- EscapeAnalysis.process(ssaMeth);
- DeadCodeRemover.process(ssaMeth);
- needsDeadCodeRemover = false;
- }
-
if (steps.contains(OptionalStep.CONST_COLLECTOR)) {
ConstCollector.process(ssaMeth);
DeadCodeRemover.process(ssaMeth);