FileDocCategorySizeDatePackage
BaseMachine.javaAPI DocAndroid 1.5 API15592Wed May 06 22:41:02 BST 2009com.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
non-null; primary arguments
private int
argCount
>= 0; number of primary arguments
private com.android.dx.rop.type.Type
auxType
null-ok; type of the operation, if salient
private int
auxInt
auxiliary int argument
private com.android.dx.rop.cst.Constant
auxCst
null-ok; auxiliary constant argument
private int
auxTarget
auxiliary branch target argument
private SwitchList
auxCases
null-ok; auxiliary switch cases argument
private ArrayList
auxInitValues
null-ok; auxiliary initial value list for newarray
private int
localIndex
>= -1; last local accessed
private com.android.dx.rop.code.RegisterSpec
localTarget
null-ok; local target spec, if salient and calculated
private com.android.dx.rop.type.TypeBearer[]
results
non-null; results
private int
resultCount
>= -1; count of the results, or -1 if no results have been set
Constructors Summary
public BaseMachine(com.android.dx.rop.type.Prototype prototype)
Constructs an instance.

param
prototype 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 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 nth primary argument.

param
n >= 0, < argCount(); which argument
return
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
>= 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
>= 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;
        localTarget = null;
        resultCount = -1;
    
protected final voidclearResult()
Clears the results.

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

return
null-ok; the argument value

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

return
null-ok; the argument value

        return auxCst;
    
protected final intgetAuxInt()
Gets the 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
null-ok; the salient type

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

return
null-ok; the argument value

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

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

        return localIndex;
    
protected final com.android.dx.rop.code.RegisterSpecgetLocalTarget()
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}.

return
null-ok; the salient register spec or 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) {
            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 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 " + type2.toHuman() +
                    " but found " + args[2].getType().toHuman());
        }
    
protected final com.android.dx.rop.type.TypeBearerresult(int n)
Gets the nth result value.

param
n >= 0, < resultCount(); which result
return
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
>= 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
>= 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 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 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());
        } else {
            ExecutionStack stack = frame.getStack();
            for (int i = 0; i < resultCount; i++) {
                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 non-null; the encountered type
param
local 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.");