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

LocalsArraySet

public class LocalsArraySet extends LocalsArray
Representation of a set of local variable arrays, with Java semantics. This peculiar case is to support in-method subroutines, which can have different locals sets for each caller.

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

Fields Summary
private final OneLocalsArray
primary
The primary LocalsArray represents the locals as seen from the subroutine itself, which is the merged representation of all the individual locals states.
private final ArrayList
secondaries
Indexed by label of caller block: the locals specific to each caller's invocation of the subroutine.
Constructors Summary
public LocalsArraySet(int maxLocals)
Constructs an instance. The locals array initially consists of all-uninitialized values (represented as {@code null}s).

param
maxLocals {@code >= 0;} the maximum number of locals this instance can refer to

        super(maxLocals != 0);
        primary = new OneLocalsArray(maxLocals);
        secondaries = new ArrayList();
    
public LocalsArraySet(OneLocalsArray primary, ArrayList secondaries)
Constructs an instance with the specified primary and secondaries set.

param
primary {@code non-null;} primary locals to use
param
secondaries {@code non-null;} secondaries set, indexed by subroutine caller label.

        super(primary.getMaxLocals() > 0);

        this.primary = primary;
        this.secondaries = secondaries;
    
private LocalsArraySet(LocalsArraySet toCopy)
Constructs an instance which is a copy of another.

param
toCopy {@code non-null;} instance to copy.

        super(toCopy.getMaxLocals() > 0);

        primary = toCopy.primary.copy();
        secondaries = new ArrayList(toCopy.secondaries.size());

        int sz = toCopy.secondaries.size();
        for (int i = 0; i < sz; i++) {
            LocalsArray la = toCopy.secondaries.get(i);

            if (la == null) {
                secondaries.add(null);
            } else {
                secondaries.add(la.copy());
            }
        }
    
Methods Summary
public voidannotate(com.android.dex.util.ExceptionWithContext ex)

inheritDoc

        ex.addContext("(locals array set; primary)");
        primary.annotate(ex);

        int sz = secondaries.size();
        for (int label = 0; label < sz; label++) {
            LocalsArray la = secondaries.get(label);

            if (la != null) {
                ex.addContext("(locals array set: primary for caller "
                        + Hex.u2(label) + ')");

                la.getPrimary().annotate(ex);
            }
        }
    
public LocalsArraycopy()

inheritDoc

        return new LocalsArraySet(this);
    
public com.android.dx.rop.type.TypeBearerget(int idx)

inheritDoc

        return primary.get(idx);
    
public com.android.dx.rop.type.TypeBearergetCategory1(int idx)

inheritDoc

        return primary.getCategory1(idx);
    
public com.android.dx.rop.type.TypeBearergetCategory2(int idx)

inheritDoc

        return primary.getCategory2(idx);
    
public intgetMaxLocals()

inheritDoc

        return primary.getMaxLocals();
    
public com.android.dx.rop.type.TypeBearergetOrNull(int idx)

inheritDoc

        return primary.getOrNull(idx);
    
protected OneLocalsArraygetPrimary()
{@inheritDoc}

        return primary;
    
private LocalsArraygetSecondaryForLabel(int label)
Gets the {@code LocalsArray} instance for a specified subroutine caller label, or null if label has no locals associated with it.

param
label {@code >= 0;} subroutine caller label
return
{@code null-ok;} locals if available.

        if (label >= secondaries.size()) {
            return null;
        }

        return secondaries.get(label);
    
public voidinvalidate(int idx)

inheritDoc

        throwIfImmutable();

        primary.invalidate(idx);

        for (LocalsArray la : secondaries) {
            if (la != null) {
                la.invalidate(idx);
            }
        }
    
public voidmakeInitialized(com.android.dx.rop.type.Type type)

inheritDoc

        int len = primary.getMaxLocals();

        if (len == 0) {
            // We have to check for this before checking for immutability.
            return;
        }

        throwIfImmutable();

        primary.makeInitialized(type);

        for (LocalsArray la : secondaries) {
            if (la != null) {
                la.makeInitialized(type);
            }
        }
    
public com.android.dx.cf.code.LocalsArraySetmerge(LocalsArray other)

inheritDoc

        LocalsArraySet result;

        try {
            if (other instanceof LocalsArraySet) {
                result = mergeWithSet((LocalsArraySet) other);
            } else {
                result = mergeWithOne((OneLocalsArray) other);
            }
        } catch (SimException ex) {
            ex.addContext("underlay locals:");
            annotate(ex);
            ex.addContext("overlay locals:");
            other.annotate(ex);
            throw ex;
        }

        result.setImmutable();
        return result;
    
private com.android.dx.cf.code.LocalsArraySetmergeWithOne(OneLocalsArray other)
Merges this set with a {@code OneLocalsArray} instance.

param
other {@code non-null;} to merge
return
{@code non-null;} this instance if merge was a no-op, or new merged instance.

        OneLocalsArray newPrimary;
        ArrayList<LocalsArray> newSecondaries;
        boolean secondariesChanged = false;

        newPrimary = primary.merge(other.getPrimary());
        newSecondaries = new ArrayList(secondaries.size());

        int sz = secondaries.size();
        for (int i = 0; i < sz; i++) {
            LocalsArray la = secondaries.get(i);
            LocalsArray resultla = null;

            if (la != null) {
                try {
                    resultla = la.merge(other);
                } catch (SimException ex) {
                    ex.addContext("Merging one locals against caller block "
                                    + Hex.u2(i));
                }
            }

            secondariesChanged = secondariesChanged || (la != resultla);

            newSecondaries.add(resultla);
        }

        if ((primary == newPrimary) && ! secondariesChanged ) {
            return this;
        }

        return new LocalsArraySet(newPrimary, newSecondaries);
    
private com.android.dx.cf.code.LocalsArraySetmergeWithSet(com.android.dx.cf.code.LocalsArraySet other)
Merges this set with another {@code LocalsArraySet} instance.

param
other {@code non-null;} to merge
return
{@code non-null;} this instance if merge was a no-op, or new merged instance.

        OneLocalsArray newPrimary;
        ArrayList<LocalsArray> newSecondaries;
        boolean secondariesChanged = false;

        newPrimary = primary.merge(other.getPrimary());

        int sz1 = secondaries.size();
        int sz2 = other.secondaries.size();
        int sz = Math.max(sz1, sz2);
        newSecondaries = new ArrayList(sz);

        for (int i = 0; i < sz; i++) {
            LocalsArray la1 = (i < sz1 ? secondaries.get(i) : null);
            LocalsArray la2 = (i < sz2 ? other.secondaries.get(i) : null);
            LocalsArray resultla = null;

            if (la1 == la2) {
                resultla = la1;
            } else if (la1 == null) {
                resultla = la2;
            } else if (la2 == null) {
                resultla = la1;
            } else {
                try {
                    resultla = la1.merge(la2);
                } catch (SimException ex) {
                    ex.addContext(
                            "Merging locals set for caller block " + Hex.u2(i));
                }
            }

            secondariesChanged = secondariesChanged || (la1 != resultla);

            newSecondaries.add(resultla);
        }

        if ((primary == newPrimary) && ! secondariesChanged ) {
            return this;
        }

        return new LocalsArraySet(newPrimary, newSecondaries);
    
public com.android.dx.cf.code.LocalsArraySetmergeWithSubroutineCaller(LocalsArray other, int predLabel)
{@inheritDoc}


        LocalsArray mine = getSecondaryForLabel(predLabel);
        LocalsArray newSecondary;
        OneLocalsArray newPrimary;

        newPrimary = primary.merge(other.getPrimary());

        if (mine == other) {
            newSecondary = mine;
        } else if (mine == null) {
            newSecondary = other;
        } else {
            newSecondary = mine.merge(other);
        }

        if ((newSecondary == mine) && (newPrimary == primary)) {
            return this;
        } else {
            /*
             * We're going to re-build a primary as a merge of all the
             * secondaries.
             */
            newPrimary = null;

            int szSecondaries = secondaries.size();
            int sz = Math.max(predLabel + 1, szSecondaries);
            ArrayList<LocalsArray> newSecondaries = new ArrayList(sz);
            for (int i = 0; i < sz; i++) {
                LocalsArray la = null;

                if (i == predLabel) {
                    /*
                     * This LocalsArray always replaces any existing one,
                     * since this is the result of a refined iteration.
                     */
                    la = newSecondary;
                } else if (i < szSecondaries) {
                    la = secondaries.get(i);
                }

                if (la != null) {
                    if (newPrimary == null) {
                        newPrimary = la.getPrimary();
                    } else {
                        newPrimary = newPrimary.merge(la.getPrimary());
                    }
                }

                newSecondaries.add(la);
            }

            LocalsArraySet result
                    = new LocalsArraySet(newPrimary, newSecondaries);
            result.setImmutable();
            return result;
        }
    
public voidset(int idx, com.android.dx.rop.type.TypeBearer type)

inheritDoc

        throwIfImmutable();

        primary.set(idx, type);

        for (LocalsArray la : secondaries) {
            if (la != null) {
                la.set(idx, type);
            }
        }
    
public voidset(com.android.dx.rop.code.RegisterSpec spec)

inheritDoc

        set(spec.getReg(), spec);
    
public voidsetImmutable()

inheritDoc

        primary.setImmutable();

        for (LocalsArray la : secondaries) {
            if (la != null) {
                la.setImmutable();
            }
        }
        super.setImmutable();
    
public LocalsArraysubArrayForLabel(int subLabel)
Returns a LocalsArray instance representing the locals state that should be used when returning to a subroutine caller.

param
subLabel {@code >= 0;} A calling label of a subroutine
return
{@code null-ok;} an instance for this subroutine, or null if subroutine is not in this set.

        LocalsArray result = getSecondaryForLabel(subLabel);
        return result;
    
public java.lang.StringtoHuman()
{@inheritDoc

        StringBuilder sb = new StringBuilder();

        sb.append("(locals array set; primary)\n");

        sb.append(getPrimary().toHuman());
        sb.append('\n");

        int sz = secondaries.size();
        for (int label = 0; label < sz; label++) {
            LocalsArray la = secondaries.get(label);

            if (la != null) {
                sb.append("(locals array set: primary for caller "
                        + Hex.u2(label) + ")\n");

                sb.append(la.getPrimary().toHuman());
                sb.append('\n");
            }
        }

        return sb.toString();