diff options
Diffstat (limited to 'dx/src/com/android/dx/cf/code/LocalVariableList.java')
-rw-r--r-- | dx/src/com/android/dx/cf/code/LocalVariableList.java | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/dx/src/com/android/dx/cf/code/LocalVariableList.java b/dx/src/com/android/dx/cf/code/LocalVariableList.java new file mode 100644 index 0000000..2962698 --- /dev/null +++ b/dx/src/com/android/dx/cf/code/LocalVariableList.java @@ -0,0 +1,373 @@ +/* + * 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.dx.rop.cst.CstString; +import com.android.dx.rop.type.Type; +import com.android.dx.rop.code.LocalItem; +import com.android.dx.util.FixedSizeList; + +/** + * List of "local variable" entries, which are the contents of + * {@code LocalVariableTable} and {@code LocalVariableTypeTable} + * attributes, as well as combinations of the two. + */ +public final class LocalVariableList extends FixedSizeList { + /** {@code non-null;} zero-size instance */ + public static final LocalVariableList EMPTY = new LocalVariableList(0); + + /** + * Returns an instance which is the concatenation of the two given + * instances. The result is immutable. + * + * @param list1 {@code non-null;} first instance + * @param list2 {@code non-null;} second instance + * @return {@code non-null;} combined instance + */ + public static LocalVariableList concat(LocalVariableList list1, + LocalVariableList list2) { + if (list1 == EMPTY) { + // easy case + return list2; + } + + int sz1 = list1.size(); + int sz2 = list2.size(); + LocalVariableList result = new LocalVariableList(sz1 + sz2); + + for (int i = 0; i < sz1; i++) { + result.set(i, list1.get(i)); + } + + for (int i = 0; i < sz2; i++) { + result.set(sz1 + i, list2.get(i)); + } + + result.setImmutable(); + return result; + } + + /** + * Returns an instance which is the result of merging the two + * given instances, where one instance should have only type + * descriptors and the other only type signatures. The merged + * result is identical to the one with descriptors, except that + * any element whose {name, index, start, length} matches an + * element in the signature list gets augmented with the + * corresponding signature. The result is immutable. + * + * @param descriptorList {@code non-null;} list with descriptors + * @param signatureList {@code non-null;} list with signatures + * @return {@code non-null;} the merged result + */ + public static LocalVariableList mergeDescriptorsAndSignatures( + LocalVariableList descriptorList, + LocalVariableList signatureList) { + int descriptorSize = descriptorList.size(); + LocalVariableList result = new LocalVariableList(descriptorSize); + + for (int i = 0; i < descriptorSize; i++) { + Item item = descriptorList.get(i); + Item signatureItem = signatureList.itemToLocal(item); + if (signatureItem != null) { + CstString signature = signatureItem.getSignature(); + item = item.withSignature(signature); + } + result.set(i, item); + } + + result.setImmutable(); + return result; + } + + /** + * Constructs an instance. + * + * @param count the number of elements to be in the list + */ + public LocalVariableList(int count) { + super(count); + } + + /** + * Gets the indicated item. + * + * @param n {@code >= 0;} which item + * @return {@code null-ok;} the indicated item + */ + public Item get(int n) { + return (Item) get0(n); + } + + /** + * Sets the item at the given index. + * + * @param n {@code >= 0, < size();} which element + * @param item {@code non-null;} the item + */ + public void set(int n, Item item) { + if (item == null) { + throw new NullPointerException("item == null"); + } + + set0(n, item); + } + + /** + * Sets the item at the given index. + * + * <p><b>Note:</b> At least one of {@code descriptor} or + * {@code signature} must be passed as non-null.</p> + * + * @param n {@code >= 0, < size();} which element + * @param startPc {@code >= 0;} the start pc of this variable's scope + * @param length {@code >= 0;} the length (in bytecodes) of this variable's + * scope + * @param name {@code non-null;} the variable's name + * @param descriptor {@code null-ok;} the variable's type descriptor + * @param signature {@code null-ok;} the variable's type signature + * @param index {@code >= 0;} the variable's local index + */ + public void set(int n, int startPc, int length, CstString name, + CstString descriptor, CstString signature, int index) { + set0(n, new Item(startPc, length, name, descriptor, signature, index)); + } + + /** + * Gets the local variable information in this instance which matches + * the given {@link com.android.dx.cf.code.LocalVariableList.Item} + * in all respects but the type descriptor and signature, if any. + * + * @param item {@code non-null;} local variable information to match + * @return {@code null-ok;} the corresponding local variable information stored + * in this instance, or {@code null} if there is no matching + * information + */ + public Item itemToLocal(Item item) { + int sz = size(); + + for (int i = 0; i < sz; i++) { + Item one = (Item) get0(i); + + if ((one != null) && one.matchesAllButType(item)) { + return one; + } + } + + return null; + } + + /** + * Gets the local variable information associated with a given address + * and local index, if any. <b>Note:</b> In standard classfiles, a + * variable's start point is listed as the address of the instruction + * <i>just past</i> the one that sets the variable. + * + * @param pc {@code >= 0;} the address to look up + * @param index {@code >= 0;} the local variable index + * @return {@code null-ok;} the associated local variable information, or + * {@code null} if none is known + */ + public Item pcAndIndexToLocal(int pc, int index) { + int sz = size(); + + for (int i = 0; i < sz; i++) { + Item one = (Item) get0(i); + + if ((one != null) && one.matchesPcAndIndex(pc, index)) { + return one; + } + } + + return null; + } + + /** + * Item in a local variable table. + */ + public static class Item { + /** {@code >= 0;} the start pc of this variable's scope */ + private final int startPc; + + /** {@code >= 0;} the length (in bytecodes) of this variable's scope */ + private final int length; + + /** {@code non-null;} the variable's name */ + private final CstString name; + + /** {@code null-ok;} the variable's type descriptor */ + private final CstString descriptor; + + /** {@code null-ok;} the variable's type signature */ + private final CstString signature; + + /** {@code >= 0;} the variable's local index */ + private final int index; + + /** + * Constructs an instance. + * + * <p><b>Note:</b> At least one of {@code descriptor} or + * {@code signature} must be passed as non-null.</p> + * + * @param startPc {@code >= 0;} the start pc of this variable's scope + * @param length {@code >= 0;} the length (in bytecodes) of this variable's + * scope + * @param name {@code non-null;} the variable's name + * @param descriptor {@code null-ok;} the variable's type descriptor + * @param signature {@code null-ok;} the variable's type signature + * @param index {@code >= 0;} the variable's local index + */ + public Item(int startPc, int length, CstString name, + CstString descriptor, CstString signature, int index) { + if (startPc < 0) { + throw new IllegalArgumentException("startPc < 0"); + } + + if (length < 0) { + throw new IllegalArgumentException("length < 0"); + } + + if (name == null) { + throw new NullPointerException("name == null"); + } + + if ((descriptor == null) && (signature == null)) { + throw new NullPointerException( + "(descriptor == null) && (signature == null)"); + } + + if (index < 0) { + throw new IllegalArgumentException("index < 0"); + } + + this.startPc = startPc; + this.length = length; + this.name = name; + this.descriptor = descriptor; + this.signature = signature; + this.index = index; + } + + /** + * Gets the start pc of this variable's scope. + * + * @return {@code >= 0;} the start pc of this variable's scope + */ + public int getStartPc() { + return startPc; + } + + /** + * Gets the length (in bytecodes) of this variable's scope. + * + * @return {@code >= 0;} the length (in bytecodes) of this variable's scope + */ + public int getLength() { + return length; + } + + /** + * Gets the variable's type descriptor. + * + * @return {@code null-ok;} the variable's type descriptor + */ + public CstString getDescriptor() { + return descriptor; + } + + /** + * Gets the variable's LocalItem, a (name, signature) tuple + * + * @return {@code null-ok;} the variable's type descriptor + */ + public LocalItem getLocalItem() { + return LocalItem.make(name, signature); + } + + /** + * Gets the variable's type signature. Private because if you need this, + * you want getLocalItem() instead. + * + * @return {@code null-ok;} the variable's type signature + */ + private CstString getSignature() { + return signature; + } + + /** + * Gets the variable's local index. + * + * @return {@code >= 0;} the variable's local index + */ + public int getIndex() { + return index; + } + + /** + * Gets the variable's type descriptor. This is a convenient shorthand + * for {@code Type.intern(getDescriptor().getString())}. + * + * @return {@code non-null;} the variable's type + */ + public Type getType() { + return Type.intern(descriptor.getString()); + } + + /** + * Constructs and returns an instance which is identical to this + * one, except that the signature is changed to the given value. + * + * @param newSignature {@code non-null;} the new signature + * @return {@code non-null;} an appropriately-constructed instance + */ + public Item withSignature(CstString newSignature) { + return new Item(startPc, length, name, descriptor, newSignature, + index); + } + + /** + * Gets whether this instance matches (describes) the given + * address and index. + * + * @param pc {@code >= 0;} the address in question + * @param index {@code >= 0;} the local variable index in question + * @return {@code true} iff this instance matches {@code pc} + * and {@code index} + */ + public boolean matchesPcAndIndex(int pc, int index) { + return (index == this.index) && + (pc >= startPc) && + (pc < (startPc + length)); + } + + /** + * Gets whether this instance matches (describes) the given + * other instance exactly in all fields except type descriptor and + * type signature. + * + * @param other {@code non-null;} the instance to compare to + * @return {@code true} iff this instance matches + */ + public boolean matchesAllButType(Item other) { + return (startPc == other.startPc) + && (length == other.length) + && (index == other.index) + && name.equals(other.name); + } + } +} |