FileDocCategorySizeDatePackage
BaseMachine.javaAPI DocAndroid 5.1 API16822Thu Mar 12 22:18:30 GMT 2015com.android.dx.cf.code

BaseMachine

public abstract class BaseMachine extends Object implements Machine
Base implementation of {@link Machine}.

Note: For the most part, the documentation for this class ignores the distinction between {@link Type} and {@link TypeBearer}.

Fields Summary
private final com.android.dx.rop.type.Prototype
prototype
private com.android.dx.rop.type.TypeBearer[]
args
{@code non-null;} primary arguments
private int
argCount
{@code >= 0;} number of primary arguments
private com.android.dx.rop.type.Type
auxType
{@code null-ok;} type of the operation, if salient
private int
auxInt
auxiliary {@code int} argument
private com.android.dx.rop.cst.Constant
auxCst
{@code null-ok;} auxiliary constant argument
private int
auxTarget
auxiliary branch target argument
private SwitchList
auxCases
{@code null-ok;} auxiliary switch cases argument
private ArrayList
auxInitValues
{@code null-ok;} auxiliary initial value list for newarray
private int
localIndex
{@code >= -1;} last local accessed
private boolean
localInfo
specifies if local has info in the local variable table
private com.android.dx.rop.code.RegisterSpec
localTarget
{@code null-ok;} local target spec, if salient and calculated
private com.android.dx.rop.type.TypeBearer[]
results
{@code non-null;} results
private int
resultCount
{@code >= -1;} count of the results, or {@code -1} if no results have been set
Constructors Summary
public BaseMachine(com.android.dx.rop.type.Prototype prototype)
Constructs an instance.

param
prototype {@code non-null;} the prototype for the associated method

        if (prototype == null) {
            throw new NullPointerException("prototype == null");
        }

        this.prototype = prototype;
        args = new TypeBearer[10];
        results = new TypeBearer[6];
        clearArgs();
    
Methods Summary
protected final voidaddResult(com.android.dx.rop.type.TypeBearer result)
Adds an additional element to the list of results.

see
#setResult
param
result {@code non-null;} result value

        if (result == null) {
            throw new NullPointerException("result == null");
        }

        results[resultCount] = result;
        resultCount++;
    
protected final com.android.dx.rop.type.TypeBearerarg(int n)
Gets the {@code n}th primary argument.

param
n {@code >= 0, < argCount();} which argument
return
{@code non-null;} the indicated argument

        if (n >= argCount) {
            throw new IllegalArgumentException("n >= argCount");
        }

        try {
            return args[n];
        } catch (ArrayIndexOutOfBoundsException ex) {
            // Translate the exception.
            throw new IllegalArgumentException("n < 0");
        }
    
protected final intargCount()
Gets the number of primary arguments.

return
{@code >= 0;} the number of primary arguments

        return argCount;
    
protected final intargWidth()
Gets the width of the arguments (where a category-2 value counts as two).

return
{@code >= 0;} the argument width

        int result = 0;

        for (int i = 0; i < argCount; i++) {
            result += args[i].getType().getCategory();
        }

        return result;
    
public final voidauxCstArg(com.android.dx.rop.cst.Constant cst)
{@inheritDoc}

        if (cst == null) {
            throw new NullPointerException("cst == null");
        }

        auxCst = cst;
    
public final voidauxInitValues(java.util.ArrayList initValues)
{@inheritDoc}

        auxInitValues = initValues;
    
public final voidauxIntArg(int value)
{@inheritDoc}

        auxInt = value;
    
public final voidauxSwitchArg(SwitchList cases)
{@inheritDoc}

        if (cases == null) {
            throw new NullPointerException("cases == null");
        }

        auxCases = cases;
    
public final voidauxTargetArg(int target)
{@inheritDoc}

        auxTarget = target;
    
public final voidauxType(com.android.dx.rop.type.Type type)
{@inheritDoc}

        auxType = type;
    
public final voidclearArgs()
{@inheritDoc}

        argCount = 0;
        auxType = null;
        auxInt = 0;
        auxCst = null;
        auxTarget = 0;
        auxCases = null;
        auxInitValues = null;
        localIndex = -1;
        localInfo = false;
        localTarget = null;
        resultCount = -1;
    
protected final voidclearResult()
Clears the results.

        resultCount = 0;
    
protected final SwitchListgetAuxCases()
Gets the switch cases auxiliary argument.

return
{@code null-ok;} the argument value

        return auxCases;
    
protected final com.android.dx.rop.cst.ConstantgetAuxCst()
Gets the constant auxiliary argument.

return
{@code null-ok;} the argument value

        return auxCst;
    
protected final intgetAuxInt()
Gets the {@code int} auxiliary argument.

return
the argument value

        return auxInt;
    
protected final intgetAuxTarget()
Gets the branch target auxiliary argument.

return
the argument value

        return auxTarget;
    
protected final com.android.dx.rop.type.TypegetAuxType()
Gets the type auxiliary argument.

return
{@code null-ok;} the salient type

        return auxType;
    
protected final java.util.ArrayListgetInitValues()
Gets the init values auxiliary argument.

return
{@code null-ok;} the argument value

        return auxInitValues;
    
protected final intgetLocalIndex()
Gets the last local index accessed.

return
{@code >= -1;} the salient local index or {@code -1} if none was set since the last time {@link #clearArgs} was called

        return localIndex;
    
protected final booleangetLocalInfo()
Gets whether the loaded local has info in the local variable table.

return
{@code true} if local arg has info in the local variable table

        return localInfo;
    
protected final com.android.dx.rop.code.RegisterSpecgetLocalTarget(boolean isMove)
Gets the target local register spec of the current operation, if any. The local target spec is the combination of the values indicated by a previous call to {@link #localTarget} with the type of what should be the sole result set by a call to {@link #setResult} (or the combination {@link #clearResult} then {@link #addResult}.

param
isMove {@code true} if the operation being performed on the local is a move. This will cause constant values to be propagated to the returned local
return
{@code null-ok;} the salient register spec or {@code null} if no local target was set since the last time {@link #clearArgs} was called

        if (localTarget == null) {
            return null;
        }

        if (resultCount != 1) {
            throw new SimException("local target with " +
                    ((resultCount == 0) ? "no" : "multiple") + " results");
        }

        TypeBearer result = results[0];
        Type resultType = result.getType();
        Type localType = localTarget.getType();

        if (resultType == localType) {
            /*
             * If this is to be a move operation and the result is a
             * known value, make the returned localTarget embody that
             * value.
             */
            if (isMove) {
                return localTarget.withType(result);
            } else {
                return localTarget;
            }
        }

        if (! Merger.isPossiblyAssignableFrom(localType, resultType)) {
            // The result and local types are inconsistent. Complain!
            throwLocalMismatch(resultType, localType);
            return null;
        }

        if (localType == Type.OBJECT) {
            /*
             * The result type is more specific than the local type,
             * so use that instead.
             */
            localTarget = localTarget.withType(result);
        }

        return localTarget;
    
public com.android.dx.rop.type.PrototypegetPrototype()
{@inheritDoc}

        return prototype;
    
public final voidlocalArg(Frame frame, int idx)
{@inheritDoc}

        clearArgs();
        args[0] = frame.getLocals().get(idx);
        argCount = 1;
        localIndex = idx;
    
public final voidlocalInfo(boolean local)
{@inheritDoc}

        localInfo = local;
    
public final voidlocalTarget(int idx, com.android.dx.rop.type.Type type, com.android.dx.rop.code.LocalItem local)
{@inheritDoc}

        localTarget = RegisterSpec.makeLocalOptional(idx, type, local);
    
public final voidpopArgs(Frame frame, int count)
{@inheritDoc}

        ExecutionStack stack = frame.getStack();

        clearArgs();

        if (count > args.length) {
            // Grow args, and add a little extra room to grow even more.
            args = new TypeBearer[count + 10];
        }

        for (int i = count - 1; i >= 0; i--) {
            args[i] = stack.pop();
        }

        argCount = count;
    
public voidpopArgs(Frame frame, com.android.dx.rop.type.Prototype prototype)
{@inheritDoc}

        StdTypeList types = prototype.getParameterTypes();
        int size = types.size();

        // Use the above method to do the actual popping...
        popArgs(frame, size);

        // ...and then verify the popped types.

        for (int i = 0; i < size; i++) {
            if (! Merger.isPossiblyAssignableFrom(types.getType(i), args[i])) {
                throw new SimException("at stack depth " + (size - 1 - i) +
                        ", expected type " + types.getType(i).toHuman() +
                        " but found " + args[i].getType().toHuman());
            }
        }
    
public final voidpopArgs(Frame frame, com.android.dx.rop.type.Type type)

        // Use the above method to do the actual popping...
        popArgs(frame, 1);

        // ...and then verify the popped type.
        if (! Merger.isPossiblyAssignableFrom(type, args[0])) {
            throw new SimException("expected type " + type.toHuman() +
                    " but found " + args[0].getType().toHuman());
        }
    
public final voidpopArgs(Frame frame, com.android.dx.rop.type.Type type1, com.android.dx.rop.type.Type type2)
{@inheritDoc}

        // Use the above method to do the actual popping...
        popArgs(frame, 2);

        // ...and then verify the popped types.

        if (! Merger.isPossiblyAssignableFrom(type1, args[0])) {
            throw new SimException("expected type " + type1.toHuman() +
                    " but found " + args[0].getType().toHuman());
        }

        if (! Merger.isPossiblyAssignableFrom(type2, args[1])) {
            throw new SimException("expected type " + type2.toHuman() +
                    " but found " + args[1].getType().toHuman());
        }
    
public final voidpopArgs(Frame frame, com.android.dx.rop.type.Type type1, com.android.dx.rop.type.Type type2, com.android.dx.rop.type.Type type3)
{@inheritDoc}

        // Use the above method to do the actual popping...
        popArgs(frame, 3);

        // ...and then verify the popped types.

        if (! Merger.isPossiblyAssignableFrom(type1, args[0])) {
            throw new SimException("expected type " + type1.toHuman() +
                    " but found " + args[0].getType().toHuman());
        }

        if (! Merger.isPossiblyAssignableFrom(type2, args[1])) {
            throw new SimException("expected type " + type2.toHuman() +
                    " but found " + args[1].getType().toHuman());
        }

        if (! Merger.isPossiblyAssignableFrom(type3, args[2])) {
            throw new SimException("expected type " + type3.toHuman() +
                    " but found " + args[2].getType().toHuman());
        }
    
protected final com.android.dx.rop.type.TypeBearerresult(int n)
Gets the {@code n}th result value.

param
n {@code >= 0, < resultCount();} which result
return
{@code non-null;} the indicated result value

        if (n >= resultCount) {
            throw new IllegalArgumentException("n >= resultCount");
        }

        try {
            return results[n];
        } catch (ArrayIndexOutOfBoundsException ex) {
            // Translate the exception.
            throw new IllegalArgumentException("n < 0");
        }
    
protected final intresultCount()
Gets the count of results. This throws an exception if results were never set. (Explicitly clearing the results counts as setting them.)

return
{@code >= 0;} the count

        if (resultCount < 0) {
            throw new SimException("results never set");
        }

        return resultCount;
    
protected final intresultWidth()
Gets the width of the results (where a category-2 value counts as two).

return
{@code >= 0;} the result width

        int width = 0;

        for (int i = 0; i < resultCount; i++) {
            width += results[i].getType().getCategory();
        }

        return width;
    
protected final voidsetResult(com.android.dx.rop.type.TypeBearer result)
Sets the results list to be the given single value.

Note: If there is more than one result value, the others may be added by using {@link #addResult}.

param
result {@code non-null;} result value

        if (result == null) {
            throw new NullPointerException("result == null");
        }

        results[0] = result;
        resultCount = 1;
    
protected final voidstoreResults(Frame frame)
Stores the results of the latest operation into the given frame. If there is a local target (see {@link #localTarget}), then the sole result is stored to that target; otherwise any results are pushed onto the stack.

param
frame {@code non-null;} frame to operate on

        if (resultCount < 0) {
            throw new SimException("results never set");
        }

        if (resultCount == 0) {
            // Nothing to do.
            return;
        }

        if (localTarget != null) {
            /*
             * Note: getLocalTarget() doesn't necessarily return
             * localTarget directly.
             */
            frame.getLocals().set(getLocalTarget(false));
        } else {
            ExecutionStack stack = frame.getStack();
            for (int i = 0; i < resultCount; i++) {
                if (localInfo) {
                    stack.setLocal();
                }
                stack.push(results[i]);
            }
        }
    
public static voidthrowLocalMismatch(com.android.dx.rop.type.TypeBearer found, com.android.dx.rop.type.TypeBearer local)
Throws an exception that indicates a mismatch in local variable types.

param
found {@code non-null;} the encountered type
param
local {@code non-null;} the local variable's claimed type

        throw new SimException("local variable type mismatch: " +
                "attempt to set or access a value of type " +
                found.toHuman() +
                " using a local variable of type " +
                local.toHuman() +
                ". This is symptomatic of .class transformation tools " +
                "that ignore local variable information.");