com.android.dx.rop.code.DexTranslationAdvice Maven / Gradle / Ivy
/*
* Copyright (C) 2007 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.rop.code;
import com.android.dx.rop.cst.CstInteger;
import com.android.dx.rop.type.Type;
/**
* Implementation of {@link TranslationAdvice} which represents what
* the dex format will be able to represent.
*/
public final class DexTranslationAdvice
implements TranslationAdvice {
/** {@code non-null;} standard instance of this class */
public static final DexTranslationAdvice THE_ONE =
new DexTranslationAdvice();
/** debug advice for disabling invoke-range optimization */
public static final DexTranslationAdvice NO_SOURCES_IN_ORDER =
new DexTranslationAdvice(true);
/**
* The minimum source width, in register units, for an invoke
* instruction that requires its sources to be in order and contiguous.
*/
private static final int MIN_INVOKE_IN_ORDER = 6;
/** when true: always returns false for requiresSourcesInOrder */
private final boolean disableSourcesInOrder;
/**
* This class is not publicly instantiable. Use {@link #THE_ONE}.
*/
private DexTranslationAdvice() {
disableSourcesInOrder = false;
}
private DexTranslationAdvice(boolean disableInvokeRange) {
this.disableSourcesInOrder = disableInvokeRange;
}
/** {@inheritDoc} */
public boolean hasConstantOperation(Rop opcode,
RegisterSpec sourceA, RegisterSpec sourceB) {
if (sourceA.getType() != Type.INT) {
return false;
}
// Return false if second source isn't a constant
if (! (sourceB.getTypeBearer() instanceof CstInteger)) {
// Except for rsub-int (reverse sub) where first source is constant
if (sourceA.getTypeBearer() instanceof CstInteger &&
opcode.getOpcode() == RegOps.SUB) {
CstInteger cst = (CstInteger) sourceA.getTypeBearer();
return cst.fitsIn16Bits();
} else {
return false;
}
}
CstInteger cst = (CstInteger) sourceB.getTypeBearer();
switch (opcode.getOpcode()) {
// These have 8 and 16 bit cst representations
case RegOps.REM:
case RegOps.ADD:
case RegOps.MUL:
case RegOps.DIV:
case RegOps.AND:
case RegOps.OR:
case RegOps.XOR:
return cst.fitsIn16Bits();
// These only have 8 bit cst reps
case RegOps.SHL:
case RegOps.SHR:
case RegOps.USHR:
return cst.fitsIn8Bits();
// No sub-const insn, so check if equivalent add-const fits
case RegOps.SUB:
CstInteger cst2 = CstInteger.make(-cst.getValue());
return cst2.fitsIn16Bits();
default:
return false;
}
}
/** {@inheritDoc} */
public boolean requiresSourcesInOrder(Rop opcode,
RegisterSpecList sources) {
return !disableSourcesInOrder && opcode.isCallLike()
&& totalRopWidth(sources) >= MIN_INVOKE_IN_ORDER;
}
/**
* Calculates the total rop width of the list of SSA registers
*
* @param sources {@code non-null;} list of SSA registers
* @return {@code >= 0;} rop-form width in register units
*/
private int totalRopWidth(RegisterSpecList sources) {
int sz = sources.size();
int total = 0;
for (int i = 0; i < sz; i++) {
total += sources.get(i).getCategory();
}
return total;
}
/** {@inheritDoc} */
public int getMaxOptimalRegisterCount() {
return 16;
}
}