com.android.dx.cf.code.LocalsArraySet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder Show documentation
Show all versions of builder Show documentation
Library to build Android applications.
/*
* 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.cf.code;
import com.android.dex.util.ExceptionWithContext;
import com.android.dx.rop.code.RegisterSpec;
import com.android.dx.rop.type.Type;
import com.android.dx.rop.type.TypeBearer;
import com.android.dx.util.Hex;
import java.util.ArrayList;
/**
* 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}.
*/
public class LocalsArraySet extends LocalsArray {
/**
* 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 OneLocalsArray primary;
/**
* Indexed by label of caller block: the locals specific to each caller's
* invocation of the subroutine.
*/
private final ArrayList secondaries;
/**
* 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
*/
public LocalsArraySet(int maxLocals) {
super(maxLocals != 0);
primary = new OneLocalsArray(maxLocals);
secondaries = new ArrayList();
}
/**
* 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.
*/
public LocalsArraySet(OneLocalsArray primary,
ArrayList secondaries) {
super(primary.getMaxLocals() > 0);
this.primary = primary;
this.secondaries = secondaries;
}
/**
* Constructs an instance which is a copy of another.
*
* @param toCopy {@code non-null;} instance to copy.
*/
private LocalsArraySet(LocalsArraySet toCopy) {
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());
}
}
}
/** @inheritDoc */
@Override
public void setImmutable() {
primary.setImmutable();
for (LocalsArray la : secondaries) {
if (la != null) {
la.setImmutable();
}
}
super.setImmutable();
}
/** @inheritDoc */
@Override
public LocalsArray copy() {
return new LocalsArraySet(this);
}
/** @inheritDoc */
@Override
public void annotate(ExceptionWithContext ex) {
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);
}
}
}
/** {@inheritDoc*/
public String toHuman() {
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();
}
/** @inheritDoc */
@Override
public void makeInitialized(Type type) {
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);
}
}
}
/** @inheritDoc */
@Override
public int getMaxLocals() {
return primary.getMaxLocals();
}
/** @inheritDoc */
@Override
public void set(int idx, TypeBearer type) {
throwIfImmutable();
primary.set(idx, type);
for (LocalsArray la : secondaries) {
if (la != null) {
la.set(idx, type);
}
}
}
/** @inheritDoc */
@Override
public void set(RegisterSpec spec) {
set(spec.getReg(), spec);
}
/** @inheritDoc */
@Override
public void invalidate(int idx) {
throwIfImmutable();
primary.invalidate(idx);
for (LocalsArray la : secondaries) {
if (la != null) {
la.invalidate(idx);
}
}
}
/** @inheritDoc */
@Override
public TypeBearer getOrNull(int idx) {
return primary.getOrNull(idx);
}
/** @inheritDoc */
@Override
public TypeBearer get(int idx) {
return primary.get(idx);
}
/** @inheritDoc */
@Override
public TypeBearer getCategory1(int idx) {
return primary.getCategory1(idx);
}
/** @inheritDoc */
@Override
public TypeBearer getCategory2(int idx) {
return primary.getCategory2(idx);
}
/**
* 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.
*/
private LocalsArraySet mergeWithSet(LocalsArraySet other) {
OneLocalsArray newPrimary;
ArrayList 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);
}
/**
* 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.
*/
private LocalsArraySet mergeWithOne(OneLocalsArray other) {
OneLocalsArray newPrimary;
ArrayList 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);
}
/** @inheritDoc */
@Override
public LocalsArraySet merge(LocalsArray other) {
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;
}
/**
* 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.
*/
private LocalsArray getSecondaryForLabel(int label) {
if (label >= secondaries.size()) {
return null;
}
return secondaries.get(label);
}
/** {@inheritDoc} */
@Override
public LocalsArraySet mergeWithSubroutineCaller
(LocalsArray other, int predLabel) {
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 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;
}
}
/**
* 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.
*/
public LocalsArray subArrayForLabel(int subLabel) {
LocalsArray result = getSecondaryForLabel(subLabel);
return result;
}
/**{@inheritDoc}*/
@Override
protected OneLocalsArray getPrimary() {
return primary;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy