diff options
Diffstat (limited to 'dx/src/com/android/dx/rop/cst')
29 files changed, 3088 insertions, 0 deletions
diff --git a/dx/src/com/android/dx/rop/cst/Constant.java b/dx/src/com/android/dx/rop/cst/Constant.java new file mode 100644 index 0000000..3ef035e --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/Constant.java @@ -0,0 +1,68 @@ +/* + * 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.rop.cst; + +import com.android.dx.util.ToHuman; + +/** + * Base class for constants of all sorts. + */ +public abstract class Constant + implements ToHuman, Comparable<Constant> { + /** + * Returns {@code true} if this instance is a category-2 constant, + * meaning it takes up two slots in the constant pool, or + * {@code false} if this instance is category-1. + * + * @return {@code true} iff this instance is category-2 + */ + public abstract boolean isCategory2(); + + /** + * Returns the human name for the particular type of constant + * this instance is. + * + * @return {@code non-null;} the name + */ + public abstract String typeName(); + + /** + * {@inheritDoc} + * + * This compares in class-major and value-minor order. + */ + public final int compareTo(Constant other) { + Class clazz = getClass(); + Class otherClazz = other.getClass(); + + if (clazz != otherClazz) { + return clazz.getName().compareTo(otherClazz.getName()); + } + + return compareTo0(other); + } + + /** + * Compare the values of this and another instance, which are guaranteed + * to be of the same class. Subclasses must implement this. + * + * @param other {@code non-null;} the instance to compare to + * @return {@code -1}, {@code 0}, or {@code 1}, as usual + * for a comparison + */ + protected abstract int compareTo0(Constant other); +} diff --git a/dx/src/com/android/dx/rop/cst/ConstantPool.java b/dx/src/com/android/dx/rop/cst/ConstantPool.java new file mode 100644 index 0000000..efc394d --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/ConstantPool.java @@ -0,0 +1,70 @@ +/* + * 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.rop.cst; + +/** + * Interface for constant pools, which are, more or less, just lists of + * {@link Constant} objects. + */ +public interface ConstantPool { + /** + * Get the "size" of the constant pool. This corresponds to the + * class file field {@code constant_pool_count}, and is in fact + * always at least one more than the actual size of the constant pool, + * as element {@code 0} is always invalid. + * + * @return {@code >= 1;} the size + */ + public int size(); + + /** + * Get the {@code n}th entry in the constant pool, which must + * be valid. + * + * @param n {@code n >= 0, n < size();} the constant pool index + * @return {@code non-null;} the corresponding entry + * @throws IllegalArgumentException thrown if {@code n} is + * in-range but invalid + */ + public Constant get(int n); + + /** + * Get the {@code n}th entry in the constant pool, which must + * be valid unless {@code n == 0}, in which case {@code null} + * is returned. + * + * @param n {@code n >= 0, n < size();} the constant pool index + * @return {@code null-ok;} the corresponding entry, if {@code n != 0} + * @throws IllegalArgumentException thrown if {@code n} is + * in-range and non-zero but invalid + */ + public Constant get0Ok(int n); + + /** + * Get the {@code n}th entry in the constant pool, or + * {@code null} if the index is in-range but invalid. In + * particular, {@code null} is returned for index {@code 0} + * as well as the index after any entry which is defined to take up + * two slots (that is, {@code Long} and {@code Double} + * entries). + * + * @param n {@code n >= 0, n < size();} the constant pool index + * @return {@code null-ok;} the corresponding entry, or {@code null} if + * the index is in-range but invalid + */ + public Constant getOrNull(int n); +} diff --git a/dx/src/com/android/dx/rop/cst/CstAnnotation.java b/dx/src/com/android/dx/rop/cst/CstAnnotation.java new file mode 100644 index 0000000..8cdf1df --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstAnnotation.java @@ -0,0 +1,96 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.annotation.Annotation; + +/** + * Constant type that represents an annotation. + */ +public final class CstAnnotation extends Constant { + /** {@code non-null;} the actual annotation */ + private final Annotation annotation; + + /** + * Constructs an instance. + * + * @param annotation {@code non-null;} the annotation to hold + */ + public CstAnnotation(Annotation annotation) { + if (annotation == null) { + throw new NullPointerException("annotation == null"); + } + + annotation.throwIfMutable(); + + this.annotation = annotation; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object other) { + if (! (other instanceof CstAnnotation)) { + return false; + } + + return annotation.equals(((CstAnnotation) other).annotation); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + return annotation.hashCode(); + } + + /** {@inheritDoc} */ + @Override + protected int compareTo0(Constant other) { + return annotation.compareTo(((CstAnnotation) other).annotation); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return annotation.toString(); + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "annotation"; + } + + /** {@inheritDoc} */ + @Override + public boolean isCategory2() { + return false; + } + + /** {@inheritDoc} */ + public String toHuman() { + return annotation.toString(); + } + + /** + * Get the underlying annotation. + * + * @return {@code non-null;} the annotation + */ + public Annotation getAnnotation() { + return annotation; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstArray.java b/dx/src/com/android/dx/rop/cst/CstArray.java new file mode 100644 index 0000000..2766b5f --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstArray.java @@ -0,0 +1,159 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; +import com.android.dx.util.FixedSizeList; + +/** + * Constant type to represent a fixed array of other constants. + */ +public final class CstArray extends Constant { + /** {@code non-null;} the actual list of contents */ + private final List list; + + /** + * Constructs an instance. + * + * @param list {@code non-null;} the actual list of contents + */ + public CstArray(List list) { + if (list == null) { + throw new NullPointerException("list == null"); + } + + list.throwIfMutable(); + + this.list = list; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object other) { + if (! (other instanceof CstArray)) { + return false; + } + + return list.equals(((CstArray) other).list); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + return list.hashCode(); + } + + /** {@inheritDoc} */ + @Override + protected int compareTo0(Constant other) { + return list.compareTo(((CstArray) other).list); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return list.toString("array{", ", ", "}"); + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "array"; + } + + /** {@inheritDoc} */ + @Override + public boolean isCategory2() { + return false; + } + + /** {@inheritDoc} */ + public String toHuman() { + return list.toHuman("{", ", ", "}"); + } + + /** + * Get the underlying list. + * + * @return {@code non-null;} the list + */ + public List getList() { + return list; + } + + /** + * List of {@link Constant} instances. + */ + public static final class List + extends FixedSizeList implements Comparable<List> { + /** + * Constructs an instance. All indices initially contain + * {@code null}. + * + * @param size the size of the list + */ + public List(int size) { + super(size); + } + + /** {@inheritDoc} */ + public int compareTo(List other) { + int thisSize = size(); + int otherSize = other.size(); + int compareSize = (thisSize < otherSize) ? thisSize : otherSize; + + for (int i = 0; i < compareSize; i++) { + Constant thisItem = (Constant) get0(i); + Constant otherItem = (Constant) other.get0(i); + int compare = thisItem.compareTo(otherItem); + if (compare != 0) { + return compare; + } + } + + if (thisSize < otherSize) { + return -1; + } else if (thisSize > otherSize) { + return 1; + } + + return 0; + } + + /** + * Gets the element at the given index. It is an error to call + * this with the index for an element which was never set; if you + * do that, this will throw {@code NullPointerException}. + * + * @param n {@code >= 0, < size();} which index + * @return {@code non-null;} element at that index + */ + public Constant get(int n) { + return (Constant) get0(n); + } + + /** + * Sets the element at the given index. + * + * @param n {@code >= 0, < size();} which index + * @param a {@code null-ok;} the element to set at {@code n} + */ + public void set(int n, Constant a) { + set0(n, a); + } + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java b/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java new file mode 100644 index 0000000..5b0aeb6 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java @@ -0,0 +1,151 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Prototype; +import com.android.dx.rop.type.Type; +import com.android.dx.rop.type.TypeBearer; + +/** + * Base class for constants of "methodish" type. + * + * <p><b>Note:</b> As a {@link TypeBearer}, this class bears the return type + * of the method.</p> + */ +public abstract class CstBaseMethodRef + extends CstMemberRef { + /** {@code non-null;} the raw prototype for this method */ + private final Prototype prototype; + + /** + * {@code null-ok;} the prototype for this method taken to be an instance + * method, or {@code null} if not yet calculated + */ + private Prototype instancePrototype; + + /** + * Constructs an instance. + * + * @param definingClass {@code non-null;} the type of the defining class + * @param nat {@code non-null;} the name-and-type + */ + /*package*/ CstBaseMethodRef(CstType definingClass, CstNat nat) { + super(definingClass, nat); + + String descriptor = getNat().getDescriptor().getString(); + this.prototype = Prototype.intern(descriptor); + this.instancePrototype = null; + } + + /** + * Gets the raw prototype of this method. This doesn't include a + * {@code this} argument. + * + * @return {@code non-null;} the method prototype + */ + public final Prototype getPrototype() { + return prototype; + } + + /** + * Gets the prototype of this method as either a + * {@code static} or instance method. In the case of a + * {@code static} method, this is the same as the raw + * prototype. In the case of an instance method, this has an + * appropriately-typed {@code this} argument as the first + * one. + * + * @param isStatic whether the method should be considered static + * @return {@code non-null;} the method prototype + */ + public final Prototype getPrototype(boolean isStatic) { + if (isStatic) { + return prototype; + } else { + if (instancePrototype == null) { + Type thisType = getDefiningClass().getClassType(); + instancePrototype = prototype.withFirstParameter(thisType); + } + return instancePrototype; + } + } + + /** {@inheritDoc} */ + @Override + protected final int compareTo0(Constant other) { + int cmp = super.compareTo0(other); + + if (cmp != 0) { + return cmp; + } + + CstBaseMethodRef otherMethod = (CstBaseMethodRef) other; + return prototype.compareTo(otherMethod.prototype); + } + + /** + * {@inheritDoc} + * + * In this case, this method returns the <i>return type</i> of this method. + * + * @return {@code non-null;} the method's return type + */ + public final Type getType() { + return prototype.getReturnType(); + } + + /** + * Gets the number of words of parameters required by this + * method's descriptor. Since instances of this class have no way + * to know if they will be used in a {@code static} or + * instance context, one has to indicate this explicitly as an + * argument. This method is just a convenient shorthand for + * {@code getPrototype().getParameterTypes().getWordCount()}, + * plus {@code 1} if the method is to be treated as an + * instance method. + * + * @param isStatic whether the method should be considered static + * @return {@code >= 0;} the argument word count + */ + public final int getParameterWordCount(boolean isStatic) { + return getPrototype(isStatic).getParameterTypes().getWordCount(); + } + + /** + * Gets whether this is a reference to an instance initialization + * method. This is just a convenient shorthand for + * {@code getNat().isInstanceInit()}. + * + * @return {@code true} iff this is a reference to an + * instance initialization method + */ + public final boolean isInstanceInit() { + return getNat().isInstanceInit(); + } + + /** + * Gets whether this is a reference to a class initialization + * method. This is just a convenient shorthand for + * {@code getNat().isClassInit()}. + * + * @return {@code true} iff this is a reference to an + * instance initialization method + */ + public final boolean isClassInit() { + return getNat().isClassInit(); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstBoolean.java b/dx/src/com/android/dx/rop/cst/CstBoolean.java new file mode 100644 index 0000000..5ff858a --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstBoolean.java @@ -0,0 +1,99 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; + +/** + * Constants of type {@code boolean}. + */ +public final class CstBoolean + extends CstLiteral32 { + /** {@code non-null;} instance representing {@code false} */ + public static final CstBoolean VALUE_FALSE = new CstBoolean(false); + + /** {@code non-null;} instance representing {@code true} */ + public static final CstBoolean VALUE_TRUE = new CstBoolean(true); + + /** + * Makes an instance for the given value. This will return an + * already-allocated instance. + * + * @param value the {@code boolean} value + * @return {@code non-null;} the appropriate instance + */ + public static CstBoolean make(boolean value) { + return value ? VALUE_TRUE : VALUE_FALSE; + } + + /** + * Makes an instance for the given {@code int} value. This + * will return an already-allocated instance. + * + * @param value must be either {@code 0} or {@code 1} + * @return {@code non-null;} the appropriate instance + */ + public static CstBoolean make(int value) { + if (value == 0) { + return VALUE_FALSE; + } else if (value == 1) { + return VALUE_TRUE; + } else { + throw new IllegalArgumentException("bogus value: " + value); + } + } + + /** + * Constructs an instance. This constructor is private; use {@link #make}. + * + * @param value the {@code boolean} value + */ + private CstBoolean(boolean value) { + super(value ? 1 : 0); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return getValue() ? "boolean{true}" : "boolean{false}"; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.BOOLEAN; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "boolean"; + } + + /** {@inheritDoc} */ + public String toHuman() { + return getValue() ? "true" : "false"; + } + + /** + * Gets the {@code boolean} value. + * + * @return the value + */ + public boolean getValue() { + return (getIntBits() == 0) ? false : true; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstByte.java b/dx/src/com/android/dx/rop/cst/CstByte.java new file mode 100644 index 0000000..fc8f58f --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstByte.java @@ -0,0 +1,99 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; +import com.android.dx.util.Hex; + +/** + * Constants of type {@code byte}. + */ +public final class CstByte + extends CstLiteral32 { + /** {@code non-null;} the value {@code 0} as an instance of this class */ + public static final CstByte VALUE_0 = make((byte) 0); + + /** + * Makes an instance for the given value. This may (but does not + * necessarily) return an already-allocated instance. + * + * @param value the {@code byte} value + */ + public static CstByte make(byte value) { + return new CstByte(value); + } + + /** + * Makes an instance for the given {@code int} value. This + * may (but does not necessarily) return an already-allocated + * instance. + * + * @param value the value, which must be in range for a {@code byte} + * @return {@code non-null;} the appropriate instance + */ + public static CstByte make(int value) { + byte cast = (byte) value; + + if (cast != value) { + throw new IllegalArgumentException("bogus byte value: " + + value); + } + + return make(cast); + } + + /** + * Constructs an instance. This constructor is private; use {@link #make}. + * + * @param value the {@code byte} value + */ + private CstByte(byte value) { + super(value); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + int value = getIntBits(); + return "byte{0x" + Hex.u1(value) + " / " + value + '}'; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.BYTE; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "byte"; + } + + /** {@inheritDoc} */ + public String toHuman() { + return Integer.toString(getIntBits()); + } + + /** + * Gets the {@code byte} value. + * + * @return the value + */ + public byte getValue() { + return (byte) getIntBits(); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstChar.java b/dx/src/com/android/dx/rop/cst/CstChar.java new file mode 100644 index 0000000..21d8b67 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstChar.java @@ -0,0 +1,99 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; +import com.android.dx.util.Hex; + +/** + * Constants of type {@code char}. + */ +public final class CstChar + extends CstLiteral32 { + /** {@code non-null;} the value {@code 0} as an instance of this class */ + public static final CstChar VALUE_0 = make((char) 0); + + /** + * Makes an instance for the given value. This may (but does not + * necessarily) return an already-allocated instance. + * + * @param value the {@code char} value + */ + public static CstChar make(char value) { + return new CstChar(value); + } + + /** + * Makes an instance for the given {@code int} value. This + * may (but does not necessarily) return an already-allocated + * instance. + * + * @param value the value, which must be in range for a {@code char} + * @return {@code non-null;} the appropriate instance + */ + public static CstChar make(int value) { + char cast = (char) value; + + if (cast != value) { + throw new IllegalArgumentException("bogus char value: " + + value); + } + + return make(cast); + } + + /** + * Constructs an instance. This constructor is private; use {@link #make}. + * + * @param value the {@code char} value + */ + private CstChar(char value) { + super(value); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + int value = getIntBits(); + return "char{0x" + Hex.u2(value) + " / " + value + '}'; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.CHAR; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "char"; + } + + /** {@inheritDoc} */ + public String toHuman() { + return Integer.toString(getIntBits()); + } + + /** + * Gets the {@code char} value. + * + * @return the value + */ + public char getValue() { + return (char) getIntBits(); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstDouble.java b/dx/src/com/android/dx/rop/cst/CstDouble.java new file mode 100644 index 0000000..8f1766f --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstDouble.java @@ -0,0 +1,90 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; +import com.android.dx.util.Hex; + +/** + * Constants of type {@code CONSTANT_Double_info}. + */ +public final class CstDouble + extends CstLiteral64 { + /** {@code non-null;} instance representing {@code 0} */ + public static final CstDouble VALUE_0 = + new CstDouble(Double.doubleToLongBits(0.0)); + + /** {@code non-null;} instance representing {@code 1} */ + public static final CstDouble VALUE_1 = + new CstDouble(Double.doubleToLongBits(1.0)); + + /** + * Makes an instance for the given value. This may (but does not + * necessarily) return an already-allocated instance. + * + * @param bits the {@code double} value as {@code long} bits + */ + public static CstDouble make(long bits) { + /* + * Note: Javadoc notwithstanding, this implementation always + * allocates. + */ + return new CstDouble(bits); + } + + /** + * Constructs an instance. This constructor is private; use {@link #make}. + * + * @param bits the {@code double} value as {@code long} bits + */ + private CstDouble(long bits) { + super(bits); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + long bits = getLongBits(); + return "double{0x" + Hex.u8(bits) + " / " + + Double.longBitsToDouble(bits) + '}'; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.DOUBLE; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "double"; + } + + /** {@inheritDoc} */ + public String toHuman() { + return Double.toString(Double.longBitsToDouble(getLongBits())); + } + + /** + * Gets the {@code double} value. + * + * @return the value + */ + public double getValue() { + return Double.longBitsToDouble(getLongBits()); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstEnumRef.java b/dx/src/com/android/dx/rop/cst/CstEnumRef.java new file mode 100644 index 0000000..641ab3f --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstEnumRef.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008 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.rop.cst; + +import com.android.dx.rop.type.Type; + +/** + * Constant type to represent a reference to a particular constant + * value of an enumerated type. + */ +public final class CstEnumRef extends CstMemberRef { + /** {@code null-ok;} the corresponding field ref, lazily initialized */ + private CstFieldRef fieldRef; + + /** + * Constructs an instance. + * + * @param nat {@code non-null;} the name-and-type; the defining class is derived + * from this + */ + public CstEnumRef(CstNat nat) { + super(new CstType(nat.getFieldType()), nat); + + fieldRef = null; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "enum"; + } + + /** + * {@inheritDoc} + * + * <b>Note:</b> This returns the enumerated type. + */ + public Type getType() { + return getDefiningClass().getClassType(); + } + + /** + * Get a {@link CstFieldRef} that corresponds with this instance. + * + * @return {@code non-null;} the corresponding field reference + */ + public CstFieldRef getFieldRef() { + if (fieldRef == null) { + fieldRef = new CstFieldRef(getDefiningClass(), getNat()); + } + + return fieldRef; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstFieldRef.java b/dx/src/com/android/dx/rop/cst/CstFieldRef.java new file mode 100644 index 0000000..a4d7180 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstFieldRef.java @@ -0,0 +1,79 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; + +/** + * Constants of type {@code CONSTANT_Fieldref_info}. + */ +public final class CstFieldRef extends CstMemberRef { + /** + * Returns an instance of this class that represents the static + * field which should hold the class corresponding to a given + * primitive type. For example, if given {@link Type#INT}, this + * method returns an instance corresponding to the field + * {@code java.lang.Integer.TYPE}. + * + * @param primitiveType {@code non-null;} the primitive type + * @return {@code non-null;} the corresponding static field + */ + public static CstFieldRef forPrimitiveType(Type primitiveType) { + return new CstFieldRef(CstType.forBoxedPrimitiveType(primitiveType), + CstNat.PRIMITIVE_TYPE_NAT); + } + + /** + * Constructs an instance. + * + * @param definingClass {@code non-null;} the type of the defining class + * @param nat {@code non-null;} the name-and-type + */ + public CstFieldRef(CstType definingClass, CstNat nat) { + super(definingClass, nat); + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "field"; + } + + /** + * Returns the type of this field. + * + * @return {@code non-null;} the field's type + */ + public Type getType() { + return getNat().getFieldType(); + } + + /** {@inheritDoc} */ + @Override + protected int compareTo0(Constant other) { + int cmp = super.compareTo0(other); + + if (cmp != 0) { + return cmp; + } + + CstFieldRef otherField = (CstFieldRef) other; + CstString thisDescriptor = getNat().getDescriptor(); + CstString otherDescriptor = otherField.getNat().getDescriptor(); + return thisDescriptor.compareTo(otherDescriptor); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstFloat.java b/dx/src/com/android/dx/rop/cst/CstFloat.java new file mode 100644 index 0000000..0a2354a --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstFloat.java @@ -0,0 +1,91 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; +import com.android.dx.util.Hex; + +/** + * Constants of type {@code CONSTANT_Float_info}. + */ +public final class CstFloat + extends CstLiteral32 { + /** {@code non-null;} instance representing {@code 0} */ + public static final CstFloat VALUE_0 = make(Float.floatToIntBits(0.0f)); + + /** {@code non-null;} instance representing {@code 1} */ + public static final CstFloat VALUE_1 = make(Float.floatToIntBits(1.0f)); + + /** {@code non-null;} instance representing {@code 2} */ + public static final CstFloat VALUE_2 = make(Float.floatToIntBits(2.0f)); + + /** + * Makes an instance for the given value. This may (but does not + * necessarily) return an already-allocated instance. + * + * @param bits the {@code float} value as {@code int} bits + */ + public static CstFloat make(int bits) { + /* + * Note: Javadoc notwithstanding, this implementation always + * allocates. + */ + return new CstFloat(bits); + } + + /** + * Constructs an instance. This constructor is private; use {@link #make}. + * + * @param bits the {@code float} value as {@code int} bits + */ + private CstFloat(int bits) { + super(bits); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + int bits = getIntBits(); + return "float{0x" + Hex.u4(bits) + " / " + + Float.intBitsToFloat(bits) + '}'; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.FLOAT; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "float"; + } + + /** {@inheritDoc} */ + public String toHuman() { + return Float.toString(Float.intBitsToFloat(getIntBits())); + } + + /** + * Gets the {@code float} value. + * + * @return the value + */ + public float getValue() { + return Float.intBitsToFloat(getIntBits()); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstInteger.java b/dx/src/com/android/dx/rop/cst/CstInteger.java new file mode 100644 index 0000000..3691fc0 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstInteger.java @@ -0,0 +1,116 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; +import com.android.dx.util.Hex; + +/** + * Constants of type {@code CONSTANT_Integer_info}. + */ +public final class CstInteger + extends CstLiteral32 { + /** {@code non-null;} array of cached instances */ + private static final CstInteger[] cache = new CstInteger[511]; + + /** {@code non-null;} instance representing {@code -1} */ + public static final CstInteger VALUE_M1 = make(-1); + + /** {@code non-null;} instance representing {@code 0} */ + public static final CstInteger VALUE_0 = make(0); + + /** {@code non-null;} instance representing {@code 1} */ + public static final CstInteger VALUE_1 = make(1); + + /** {@code non-null;} instance representing {@code 2} */ + public static final CstInteger VALUE_2 = make(2); + + /** {@code non-null;} instance representing {@code 3} */ + public static final CstInteger VALUE_3 = make(3); + + /** {@code non-null;} instance representing {@code 4} */ + public static final CstInteger VALUE_4 = make(4); + + /** {@code non-null;} instance representing {@code 5} */ + public static final CstInteger VALUE_5 = make(5); + + /** + * Makes an instance for the given value. This may (but does not + * necessarily) return an already-allocated instance. + * + * @param value the {@code int} value + * @return {@code non-null;} the appropriate instance + */ + public static CstInteger make(int value) { + /* + * Note: No need to synchronize, since we don't make any sort + * of guarantee about ==, and it's okay to overwrite existing + * entries too. + */ + int idx = (value & 0x7fffffff) % cache.length; + CstInteger obj = cache[idx]; + + if ((obj != null) && (obj.getValue() == value)) { + return obj; + } + + obj = new CstInteger(value); + cache[idx] = obj; + return obj; + } + + /** + * Constructs an instance. This constructor is private; use {@link #make}. + * + * @param value the {@code int} value + */ + private CstInteger(int value) { + super(value); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + int value = getIntBits(); + return "int{0x" + Hex.u4(value) + " / " + value + '}'; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.INT; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "int"; + } + + /** {@inheritDoc} */ + public String toHuman() { + return Integer.toString(getIntBits()); + } + + /** + * Gets the {@code int} value. + * + * @return the value + */ + public int getValue() { + return getIntBits(); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java b/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java new file mode 100644 index 0000000..8b8cb30 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java @@ -0,0 +1,60 @@ +/* + * 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.rop.cst; + +/** + * Constants of type {@code CONSTANT_InterfaceMethodref_info}. + */ +public final class CstInterfaceMethodRef + extends CstBaseMethodRef { + /** + * {@code null-ok;} normal {@link CstMethodRef} that corresponds to this + * instance, if calculated + */ + private CstMethodRef methodRef; + + /** + * Constructs an instance. + * + * @param definingClass {@code non-null;} the type of the defining class + * @param nat {@code non-null;} the name-and-type + */ + public CstInterfaceMethodRef(CstType definingClass, CstNat nat) { + super(definingClass, nat); + methodRef = null; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "ifaceMethod"; + } + + /** + * Gets a normal (non-interface) {@link CstMethodRef} that corresponds to + * this instance. + * + * @return {@code non-null;} an appropriate instance + */ + public CstMethodRef toMethodRef() { + if (methodRef == null) { + methodRef = new CstMethodRef(getDefiningClass(), getNat()); + } + + return methodRef; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstKnownNull.java b/dx/src/com/android/dx/rop/cst/CstKnownNull.java new file mode 100644 index 0000000..a80322c --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstKnownNull.java @@ -0,0 +1,110 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; + +/** + * Constant type to represent a known-{@code null} value. + */ +public final class CstKnownNull extends CstLiteralBits { + /** {@code non-null;} unique instance of this class */ + public static final CstKnownNull THE_ONE = new CstKnownNull(); + + /** + * Constructs an instance. This class is not publicly instantiable. Use + * {@link #THE_ONE}. + */ + private CstKnownNull() { + // This space intentionally left blank. + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object other) { + return (other instanceof CstKnownNull); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + return 0x4466757a; + } + + /** {@inheritDoc} */ + @Override + protected int compareTo0(Constant other) { + return 0; + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return "known-null"; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.KNOWN_NULL; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "known-null"; + } + + /** {@inheritDoc} */ + @Override + public boolean isCategory2() { + return false; + } + + /** {@inheritDoc} */ + public String toHuman() { + return "null"; + } + + /** {@inheritDoc} */ + @Override + public boolean fitsInInt() { + // See comment in getIntBits(). + return true; + } + + /** + * {@inheritDoc} + * + * As "literal bits," a known-null is always represented as the + * number zero. + */ + @Override + public int getIntBits() { + return 0; + } + + /** + * {@inheritDoc} + * + * As "literal bits," a known-null is always represented as the + * number zero. + */ + @Override + public long getLongBits() { + return 0; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral32.java b/dx/src/com/android/dx/rop/cst/CstLiteral32.java new file mode 100644 index 0000000..042cbd9 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstLiteral32.java @@ -0,0 +1,87 @@ +/* + * 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.rop.cst; + +/** + * Constants which are literal 32-bit values of some sort. + */ +public abstract class CstLiteral32 + extends CstLiteralBits { + /** the value as {@code int} bits */ + private final int bits; + + /** + * Constructs an instance. + * + * @param bits the value as {@code int} bits + */ + /*package*/ CstLiteral32(int bits) { + this.bits = bits; + } + + /** {@inheritDoc} */ + @Override + public final boolean equals(Object other) { + return (other != null) && + (getClass() == other.getClass()) && + bits == ((CstLiteral32) other).bits; + } + + /** {@inheritDoc} */ + @Override + public final int hashCode() { + return bits; + } + + /** {@inheritDoc} */ + @Override + protected int compareTo0(Constant other) { + int otherBits = ((CstLiteral32) other).bits; + + if (bits < otherBits) { + return -1; + } else if (bits > otherBits) { + return 1; + } else { + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public final boolean isCategory2() { + return false; + } + + /** {@inheritDoc} */ + @Override + public final boolean fitsInInt() { + return true; + } + + /** {@inheritDoc} */ + @Override + public final int getIntBits() { + return bits; + } + + /** {@inheritDoc} */ + @Override + public final long getLongBits() { + return (long) bits; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral64.java b/dx/src/com/android/dx/rop/cst/CstLiteral64.java new file mode 100644 index 0000000..94cfa8c --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstLiteral64.java @@ -0,0 +1,87 @@ +/* + * 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.rop.cst; + +/** + * Constants which are literal 64-bit values of some sort. + */ +public abstract class CstLiteral64 + extends CstLiteralBits { + /** the value as {@code long} bits */ + private final long bits; + + /** + * Constructs an instance. + * + * @param bits the value as {@code long} bits + */ + /*package*/ CstLiteral64(long bits) { + this.bits = bits; + } + + /** {@inheritDoc} */ + @Override + public final boolean equals(Object other) { + return (other != null) && + (getClass() == other.getClass()) && + bits == ((CstLiteral64) other).bits; + } + + /** {@inheritDoc} */ + @Override + public final int hashCode() { + return (int) bits ^ (int) (bits >> 32); + } + + /** {@inheritDoc} */ + @Override + protected int compareTo0(Constant other) { + long otherBits = ((CstLiteral64) other).bits; + + if (bits < otherBits) { + return -1; + } else if (bits > otherBits) { + return 1; + } else { + return 0; + } + } + + /** {@inheritDoc} */ + @Override + public final boolean isCategory2() { + return true; + } + + /** {@inheritDoc} */ + @Override + public final boolean fitsInInt() { + return (int) bits == bits; + } + + /** {@inheritDoc} */ + @Override + public final int getIntBits() { + return (int) bits; + } + + /** {@inheritDoc} */ + @Override + public final long getLongBits() { + return bits; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstLiteralBits.java b/dx/src/com/android/dx/rop/cst/CstLiteralBits.java new file mode 100644 index 0000000..8bf13a2 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstLiteralBits.java @@ -0,0 +1,82 @@ +/* + * 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.rop.cst; + +/** + * Constants which are literal bitwise values of some sort. + */ +public abstract class CstLiteralBits + extends TypedConstant { + /** + * Returns whether or not this instance's value may be accurately + * represented as an {@code int}. The rule is that if there + * is an {@code int} which may be sign-extended to yield this + * instance's value, then this method returns {@code true}. + * Otherwise, it returns {@code false}. + * + * @return {@code true} iff this instance fits in an {@code int} + */ + public abstract boolean fitsInInt(); + + /** + * Gets the value as {@code int} bits. If this instance contains + * more bits than fit in an {@code int}, then this returns only + * the low-order bits. + * + * @return the bits + */ + public abstract int getIntBits(); + + /** + * Gets the value as {@code long} bits. If this instance contains + * fewer bits than fit in a {@code long}, then the result of this + * method is the sign extension of the value. + * + * @return the bits + */ + public abstract long getLongBits(); + + /** + * Returns true if this value can fit in 16 bits with sign-extension. + * + * @return true if the sign-extended lower 16 bits are the same as + * the value. + */ + public boolean fitsIn16Bits() { + if (! fitsInInt()) { + return false; + } + + int bits = getIntBits(); + return (short) bits == bits; + } + + /** + * Returns true if this value can fit in 8 bits with sign-extension. + * + * @return true if the sign-extended lower 8 bits are the same as + * the value. + */ + public boolean fitsIn8Bits() { + if (! fitsInInt()) { + return false; + } + + int bits = getIntBits(); + return (byte) bits == bits; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstLong.java b/dx/src/com/android/dx/rop/cst/CstLong.java new file mode 100644 index 0000000..d159529 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstLong.java @@ -0,0 +1,87 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; +import com.android.dx.util.Hex; + +/** + * Constants of type {@code CONSTANT_Long_info}. + */ +public final class CstLong + extends CstLiteral64 { + /** {@code non-null;} instance representing {@code 0} */ + public static final CstLong VALUE_0 = make(0); + + /** {@code non-null;} instance representing {@code 1} */ + public static final CstLong VALUE_1 = make(1); + + /** + * Makes an instance for the given value. This may (but does not + * necessarily) return an already-allocated instance. + * + * @param value the {@code long} value + */ + public static CstLong make(long value) { + /* + * Note: Javadoc notwithstanding, this implementation always + * allocates. + */ + return new CstLong(value); + } + + /** + * Constructs an instance. This constructor is private; use {@link #make}. + * + * @param value the {@code long} value + */ + private CstLong(long value) { + super(value); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + long value = getLongBits(); + return "long{0x" + Hex.u8(value) + " / " + value + '}'; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.LONG; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "long"; + } + + /** {@inheritDoc} */ + public String toHuman() { + return Long.toString(getLongBits()); + } + + /** + * Gets the {@code long} value. + * + * @return the value + */ + public long getValue() { + return getLongBits(); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstMemberRef.java b/dx/src/com/android/dx/rop/cst/CstMemberRef.java new file mode 100644 index 0000000..1775398 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstMemberRef.java @@ -0,0 +1,122 @@ +/* + * 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.rop.cst; + +/** + * Constants of type {@code CONSTANT_*ref_info}. + */ +public abstract class CstMemberRef extends TypedConstant { + /** {@code non-null;} the type of the defining class */ + private final CstType definingClass; + + /** {@code non-null;} the name-and-type */ + private final CstNat nat; + + /** + * Constructs an instance. + * + * @param definingClass {@code non-null;} the type of the defining class + * @param nat {@code non-null;} the name-and-type + */ + /*package*/ CstMemberRef(CstType definingClass, CstNat nat) { + if (definingClass == null) { + throw new NullPointerException("definingClass == null"); + } + + if (nat == null) { + throw new NullPointerException("nat == null"); + } + + this.definingClass = definingClass; + this.nat = nat; + } + + /** {@inheritDoc} */ + @Override + public final boolean equals(Object other) { + if ((other == null) || (getClass() != other.getClass())) { + return false; + } + + CstMemberRef otherRef = (CstMemberRef) other; + return definingClass.equals(otherRef.definingClass) && + nat.equals(otherRef.nat); + } + + /** {@inheritDoc} */ + @Override + public final int hashCode() { + return (definingClass.hashCode() * 31) ^ nat.hashCode(); + } + + /** + * {@inheritDoc} + * + * <p><b>Note:</b> This implementation just compares the defining + * class and name, and it is up to subclasses to compare the rest + * after calling {@code super.compareTo0()}.</p> + */ + @Override + protected int compareTo0(Constant other) { + CstMemberRef otherMember = (CstMemberRef) other; + int cmp = definingClass.compareTo(otherMember.definingClass); + + if (cmp != 0) { + return cmp; + } + + CstString thisName = nat.getName(); + CstString otherName = otherMember.nat.getName(); + + return thisName.compareTo(otherName); + } + + /** {@inheritDoc} */ + @Override + public final String toString() { + return typeName() + '{' + toHuman() + '}'; + } + + /** {@inheritDoc} */ + @Override + public final boolean isCategory2() { + return false; + } + + /** {@inheritDoc} */ + public final String toHuman() { + return definingClass.toHuman() + '.' + nat.toHuman(); + } + + /** + * Gets the type of the defining class. + * + * @return {@code non-null;} the type of defining class + */ + public final CstType getDefiningClass() { + return definingClass; + } + + /** + * Gets the defining name-and-type. + * + * @return {@code non-null;} the name-and-type + */ + public final CstNat getNat() { + return nat; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstMethodRef.java b/dx/src/com/android/dx/rop/cst/CstMethodRef.java new file mode 100644 index 0000000..075bc7c --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstMethodRef.java @@ -0,0 +1,39 @@ +/* + * 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.rop.cst; + +/** + * Constants of type {@code CONSTANT_Methodref_info}. + */ +public final class CstMethodRef + extends CstBaseMethodRef { + /** + * Constructs an instance. + * + * @param definingClass {@code non-null;} the type of the defining class + * @param nat {@code non-null;} the name-and-type + */ + public CstMethodRef(CstType definingClass, CstNat nat) { + super(definingClass, nat); + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "method"; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstNat.java b/dx/src/com/android/dx/rop/cst/CstNat.java new file mode 100644 index 0000000..cd067e9 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstNat.java @@ -0,0 +1,170 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; + +/** + * Constants of type {@code CONSTANT_NameAndType_info}. + */ +public final class CstNat extends Constant { + /** + * {@code non-null;} the instance for name {@code TYPE} and descriptor + * {@code java.lang.Class}, which is useful when dealing with + * wrapped primitives + */ + public static final CstNat PRIMITIVE_TYPE_NAT = + new CstNat(new CstString("TYPE"), + new CstString("Ljava/lang/Class;")); + + /** {@code non-null;} the name */ + private final CstString name; + + /** {@code non-null;} the descriptor (type) */ + private final CstString descriptor; + + /** + * Constructs an instance. + * + * @param name {@code non-null;} the name + * @param descriptor {@code non-null;} the descriptor + */ + public CstNat(CstString name, CstString descriptor) { + if (name == null) { + throw new NullPointerException("name == null"); + } + + if (descriptor == null) { + throw new NullPointerException("descriptor == null"); + } + + this.name = name; + this.descriptor = descriptor; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object other) { + if (!(other instanceof CstNat)) { + return false; + } + + CstNat otherNat = (CstNat) other; + return name.equals(otherNat.name) && + descriptor.equals(otherNat.descriptor); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + return (name.hashCode() * 31) ^ descriptor.hashCode(); + } + + /** {@inheritDoc} */ + @Override + protected int compareTo0(Constant other) { + CstNat otherNat = (CstNat) other; + int cmp = name.compareTo(otherNat.name); + + if (cmp != 0) { + return cmp; + } + + return descriptor.compareTo(otherNat.descriptor); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return "nat{" + toHuman() + '}'; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "nat"; + } + + /** {@inheritDoc} */ + @Override + public boolean isCategory2() { + return false; + } + + /** + * Gets the name. + * + * @return {@code non-null;} the name + */ + public CstString getName() { + return name; + } + + /** + * Gets the descriptor. + * + * @return {@code non-null;} the descriptor + */ + public CstString getDescriptor() { + return descriptor; + } + + /** + * Returns an unadorned but human-readable version of the name-and-type + * value. + * + * @return {@code non-null;} the human form + */ + public String toHuman() { + return name.toHuman() + ':' + descriptor.toHuman(); + } + + /** + * Gets the field type corresponding to this instance's descriptor. + * This method is only valid to call if the descriptor in fact describes + * a field (and not a method). + * + * @return {@code non-null;} the field type + */ + public Type getFieldType() { + return Type.intern(descriptor.getString()); + } + + /** + * Gets whether this instance has the name of a standard instance + * initialization method. This is just a convenient shorthand for + * {@code getName().getString().equals("<init>")}. + * + * @return {@code true} iff this is a reference to an + * instance initialization method + */ + public final boolean isInstanceInit() { + return name.getString().equals("<init>"); + } + + /** + * Gets whether this instance has the name of a standard class + * initialization method. This is just a convenient shorthand for + * {@code getName().getString().equals("<clinit>")}. + * + * @return {@code true} iff this is a reference to an + * instance initialization method + */ + public final boolean isClassInit() { + return name.getString().equals("<clinit>"); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstShort.java b/dx/src/com/android/dx/rop/cst/CstShort.java new file mode 100644 index 0000000..5be1022 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstShort.java @@ -0,0 +1,100 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; +import com.android.dx.util.Hex; + +/** + * Constants of type {@code short}. + */ +public final class CstShort + extends CstLiteral32 { + /** {@code non-null;} the value {@code 0} as an instance of this class */ + public static final CstShort VALUE_0 = make((short) 0); + + /** + * Makes an instance for the given value. This may (but does not + * necessarily) return an already-allocated instance. + * + * @param value the {@code short} value + * @return {@code non-null;} the appropriate instance + */ + public static CstShort make(short value) { + return new CstShort(value); + } + + /** + * Makes an instance for the given {@code int} value. This + * may (but does not necessarily) return an already-allocated + * instance. + * + * @param value the value, which must be in range for a {@code short} + * @return {@code non-null;} the appropriate instance + */ + public static CstShort make(int value) { + short cast = (short) value; + + if (cast != value) { + throw new IllegalArgumentException("bogus short value: " + + value); + } + + return make(cast); + } + + /** + * Constructs an instance. This constructor is private; use {@link #make}. + * + * @param value the {@code short} value + */ + private CstShort(short value) { + super(value); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + int value = getIntBits(); + return "short{0x" + Hex.u2(value) + " / " + value + '}'; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.SHORT; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "short"; + } + + /** {@inheritDoc} */ + public String toHuman() { + return Integer.toString(getIntBits()); + } + + /** + * Gets the {@code short} value. + * + * @return the value + */ + public short getValue() { + return (short) getIntBits(); + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstString.java b/dx/src/com/android/dx/rop/cst/CstString.java new file mode 100644 index 0000000..a778e97 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstString.java @@ -0,0 +1,375 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; +import com.android.dx.util.ByteArray; +import com.android.dx.util.Hex; + +/** + * Constants of type {@code CONSTANT_Utf8_info} or {@code CONSTANT_String_info}. + */ +public final class CstString extends TypedConstant { + /** + * {@code non-null;} instance representing {@code ""}, that is, the + * empty string + */ + public static final CstString EMPTY_STRING = new CstString(""); + + /** {@code non-null;} the UTF-8 value as a string */ + private final String string; + + /** {@code non-null;} the UTF-8 value as bytes */ + private final ByteArray bytes; + + /** + * Converts a string into its MUTF-8 form. MUTF-8 differs from normal UTF-8 + * in the handling of character '\0' and surrogate pairs. + * + * @param string {@code non-null;} the string to convert + * @return {@code non-null;} the UTF-8 bytes for it + */ + public static byte[] stringToUtf8Bytes(String string) { + int len = string.length(); + byte[] bytes = new byte[len * 3]; // Avoid having to reallocate. + int outAt = 0; + + for (int i = 0; i < len; i++) { + char c = string.charAt(i); + if ((c != 0) && (c < 0x80)) { + bytes[outAt] = (byte) c; + outAt++; + } else if (c < 0x800) { + bytes[outAt] = (byte) (((c >> 6) & 0x1f) | 0xc0); + bytes[outAt + 1] = (byte) ((c & 0x3f) | 0x80); + outAt += 2; + } else { + bytes[outAt] = (byte) (((c >> 12) & 0x0f) | 0xe0); + bytes[outAt + 1] = (byte) (((c >> 6) & 0x3f) | 0x80); + bytes[outAt + 2] = (byte) ((c & 0x3f) | 0x80); + outAt += 3; + } + } + + byte[] result = new byte[outAt]; + System.arraycopy(bytes, 0, result, 0, outAt); + return result; + } + + /** + * Converts an array of UTF-8 bytes into a string. + * + * @param bytes {@code non-null;} the bytes to convert + * @return {@code non-null;} the converted string + */ + public static String utf8BytesToString(ByteArray bytes) { + int length = bytes.size(); + char[] chars = new char[length]; // This is sized to avoid a realloc. + int outAt = 0; + + for (int at = 0; length > 0; /*at*/) { + int v0 = bytes.getUnsignedByte(at); + char out; + switch (v0 >> 4) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: { + // 0XXXXXXX -- single-byte encoding + length--; + if (v0 == 0) { + // A single zero byte is illegal. + return throwBadUtf8(v0, at); + } + out = (char) v0; + at++; + break; + } + case 0x0c: case 0x0d: { + // 110XXXXX -- two-byte encoding + length -= 2; + if (length < 0) { + return throwBadUtf8(v0, at); + } + int v1 = bytes.getUnsignedByte(at + 1); + if ((v1 & 0xc0) != 0x80) { + return throwBadUtf8(v1, at + 1); + } + int value = ((v0 & 0x1f) << 6) | (v1 & 0x3f); + if ((value != 0) && (value < 0x80)) { + /* + * This should have been represented with + * one-byte encoding. + */ + return throwBadUtf8(v1, at + 1); + } + out = (char) value; + at += 2; + break; + } + case 0x0e: { + // 1110XXXX -- three-byte encoding + length -= 3; + if (length < 0) { + return throwBadUtf8(v0, at); + } + int v1 = bytes.getUnsignedByte(at + 1); + if ((v1 & 0xc0) != 0x80) { + return throwBadUtf8(v1, at + 1); + } + int v2 = bytes.getUnsignedByte(at + 2); + if ((v1 & 0xc0) != 0x80) { + return throwBadUtf8(v2, at + 2); + } + int value = ((v0 & 0x0f) << 12) | ((v1 & 0x3f) << 6) | + (v2 & 0x3f); + if (value < 0x800) { + /* + * This should have been represented with one- or + * two-byte encoding. + */ + return throwBadUtf8(v2, at + 2); + } + out = (char) value; + at += 3; + break; + } + default: { + // 10XXXXXX, 1111XXXX -- illegal + return throwBadUtf8(v0, at); + } + } + chars[outAt] = out; + outAt++; + } + + return new String(chars, 0, outAt); + } + + /** + * Helper for {@link #utf8BytesToString}, which throws the right + * exception for a bogus utf-8 byte. + * + * @param value the byte value + * @param offset the file offset + * @return never + * @throws IllegalArgumentException always thrown + */ + private static String throwBadUtf8(int value, int offset) { + throw new IllegalArgumentException("bad utf-8 byte " + Hex.u1(value) + + " at offset " + Hex.u4(offset)); + } + + /** + * Constructs an instance from a {@code String}. + * + * @param string {@code non-null;} the UTF-8 value as a string + */ + public CstString(String string) { + if (string == null) { + throw new NullPointerException("string == null"); + } + + this.string = string.intern(); + this.bytes = new ByteArray(stringToUtf8Bytes(string)); + } + + /** + * Constructs an instance from some UTF-8 bytes. + * + * @param bytes {@code non-null;} array of the UTF-8 bytes + */ + public CstString(ByteArray bytes) { + if (bytes == null) { + throw new NullPointerException("bytes == null"); + } + + this.bytes = bytes; + this.string = utf8BytesToString(bytes).intern(); + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object other) { + if (!(other instanceof CstString)) { + return false; + } + + return string.equals(((CstString) other).string); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + return string.hashCode(); + } + + /** {@inheritDoc} */ + @Override + protected int compareTo0(Constant other) { + return string.compareTo(((CstString) other).string); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return "string{\"" + toHuman() + "\"}"; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "utf8"; + } + + /** {@inheritDoc} */ + @Override + public boolean isCategory2() { + return false; + } + + /** {@inheritDoc} */ + public String toHuman() { + int len = string.length(); + StringBuilder sb = new StringBuilder(len * 3 / 2); + + for (int i = 0; i < len; i++) { + char c = string.charAt(i); + if ((c >= ' ') && (c < 0x7f)) { + if ((c == '\'') || (c == '\"') || (c == '\\')) { + sb.append('\\'); + } + sb.append(c); + } else if (c <= 0x7f) { + switch (c) { + case '\n': sb.append("\\n"); break; + case '\r': sb.append("\\r"); break; + case '\t': sb.append("\\t"); break; + default: { + /* + * Represent the character as an octal escape. + * If the next character is a valid octal + * digit, disambiguate by using the + * three-digit form. + */ + char nextChar = + (i < (len - 1)) ? string.charAt(i + 1) : 0; + boolean displayZero = + (nextChar >= '0') && (nextChar <= '7'); + sb.append('\\'); + for (int shift = 6; shift >= 0; shift -= 3) { + char outChar = (char) (((c >> shift) & 7) + '0'); + if ((outChar != '0') || displayZero) { + sb.append(outChar); + displayZero = true; + } + } + if (! displayZero) { + // Ironic edge case: The original value was 0. + sb.append('0'); + } + break; + } + } + } else { + sb.append("\\u"); + sb.append(Character.forDigit(c >> 12, 16)); + sb.append(Character.forDigit((c >> 8) & 0x0f, 16)); + sb.append(Character.forDigit((c >> 4) & 0x0f, 16)); + sb.append(Character.forDigit(c & 0x0f, 16)); + } + } + + return sb.toString(); + } + + /** + * Gets the value as a human-oriented string, surrounded by double + * quotes. + * + * @return {@code non-null;} the quoted string + */ + public String toQuoted() { + return '\"' + toHuman() + '\"'; + } + + /** + * Gets the value as a human-oriented string, surrounded by double + * quotes, but ellipsizes the result if it is longer than the given + * maximum length + * + * @param maxLength {@code >= 5;} the maximum length of the string to return + * @return {@code non-null;} the quoted string + */ + public String toQuoted(int maxLength) { + String string = toHuman(); + int length = string.length(); + String ellipses; + + if (length <= (maxLength - 2)) { + ellipses = ""; + } else { + string = string.substring(0, maxLength - 5); + ellipses = "..."; + } + + return '\"' + string + ellipses + '\"'; + } + + /** + * Gets the UTF-8 value as a string. + * The returned string is always already interned. + * + * @return {@code non-null;} the UTF-8 value as a string + */ + public String getString() { + return string; + } + + /** + * Gets the UTF-8 value as UTF-8 encoded bytes. + * + * @return {@code non-null;} an array of the UTF-8 bytes + */ + public ByteArray getBytes() { + return bytes; + } + + /** + * Gets the size of this instance as UTF-8 code points. That is, + * get the number of bytes in the UTF-8 encoding of this instance. + * + * @return {@code >= 0;} the UTF-8 size + */ + public int getUtf8Size() { + return bytes.size(); + } + + /** + * Gets the size of this instance as UTF-16 code points. That is, + * get the number of 16-bit chars in the UTF-16 encoding of this + * instance. This is the same as the {@code length} of the + * Java {@code String} representation of this instance. + * + * @return {@code >= 0;} the UTF-16 size + */ + public int getUtf16Size() { + return string.length(); + } + + public Type getType() { + return Type.STRING; + } +} diff --git a/dx/src/com/android/dx/rop/cst/CstType.java b/dx/src/com/android/dx/rop/cst/CstType.java new file mode 100644 index 0000000..8624028 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/CstType.java @@ -0,0 +1,232 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.Type; + +import java.util.HashMap; + +/** + * Constants that represent an arbitrary type (reference or primitive). + */ +public final class CstType extends TypedConstant { + /** {@code non-null;} map of interned types */ + private static final HashMap<Type, CstType> interns = + new HashMap<Type, CstType>(100); + + /** {@code non-null;} instance corresponding to the class {@code Object} */ + public static final CstType OBJECT = intern(Type.OBJECT); + + /** {@code non-null;} instance corresponding to the class {@code Boolean} */ + public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS); + + /** {@code non-null;} instance corresponding to the class {@code Byte} */ + public static final CstType BYTE = intern(Type.BYTE_CLASS); + + /** {@code non-null;} instance corresponding to the class {@code Character} */ + public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS); + + /** {@code non-null;} instance corresponding to the class {@code Double} */ + public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS); + + /** {@code non-null;} instance corresponding to the class {@code Float} */ + public static final CstType FLOAT = intern(Type.FLOAT_CLASS); + + /** {@code non-null;} instance corresponding to the class {@code Long} */ + public static final CstType LONG = intern(Type.LONG_CLASS); + + /** {@code non-null;} instance corresponding to the class {@code Integer} */ + public static final CstType INTEGER = intern(Type.INTEGER_CLASS); + + /** {@code non-null;} instance corresponding to the class {@code Short} */ + public static final CstType SHORT = intern(Type.SHORT_CLASS); + + /** {@code non-null;} instance corresponding to the class {@code Void} */ + public static final CstType VOID = intern(Type.VOID_CLASS); + + /** {@code non-null;} instance corresponding to the type {@code boolean[]} */ + public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY); + + /** {@code non-null;} instance corresponding to the type {@code byte[]} */ + public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY); + + /** {@code non-null;} instance corresponding to the type {@code char[]} */ + public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY); + + /** {@code non-null;} instance corresponding to the type {@code double[]} */ + public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY); + + /** {@code non-null;} instance corresponding to the type {@code float[]} */ + public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY); + + /** {@code non-null;} instance corresponding to the type {@code long[]} */ + public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY); + + /** {@code non-null;} instance corresponding to the type {@code int[]} */ + public static final CstType INT_ARRAY = intern(Type.INT_ARRAY); + + /** {@code non-null;} instance corresponding to the type {@code short[]} */ + public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY); + + /** {@code non-null;} the underlying type */ + private final Type type; + + /** + * {@code null-ok;} the type descriptor corresponding to this instance, if + * calculated + */ + private CstString descriptor; + + /** + * Returns an instance of this class that represents the wrapper + * class corresponding to a given primitive type. For example, if + * given {@link Type#INT}, this method returns the class reference + * {@code java.lang.Integer}. + * + * @param primitiveType {@code non-null;} the primitive type + * @return {@code non-null;} the corresponding wrapper class + */ + public static CstType forBoxedPrimitiveType(Type primitiveType) { + switch (primitiveType.getBasicType()) { + case Type.BT_BOOLEAN: return BOOLEAN; + case Type.BT_BYTE: return BYTE; + case Type.BT_CHAR: return CHARACTER; + case Type.BT_DOUBLE: return DOUBLE; + case Type.BT_FLOAT: return FLOAT; + case Type.BT_INT: return INTEGER; + case Type.BT_LONG: return LONG; + case Type.BT_SHORT: return SHORT; + case Type.BT_VOID: return VOID; + } + + throw new IllegalArgumentException("not primitive: " + primitiveType); + } + + /** + * Returns an interned instance of this class for the given type. + * + * @param type {@code non-null;} the underlying type + * @return {@code non-null;} an appropriately-constructed instance + */ + public static CstType intern(Type type) { + synchronized (interns) { + CstType cst = interns.get(type); + + if (cst == null) { + cst = new CstType(type); + interns.put(type, cst); + } + + return cst; + } + } + + /** + * Constructs an instance. + * + * @param type {@code non-null;} the underlying type + */ + public CstType(Type type) { + if (type == null) { + throw new NullPointerException("type == null"); + } + + if (type == type.KNOWN_NULL) { + throw new UnsupportedOperationException( + "KNOWN_NULL is not representable"); + } + + this.type = type; + this.descriptor = null; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object other) { + if (!(other instanceof CstType)) { + return false; + } + + return type == ((CstType) other).type; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + return type.hashCode(); + } + + /** {@inheritDoc} */ + @Override + protected int compareTo0(Constant other) { + String thisDescriptor = type.getDescriptor(); + String otherDescriptor = ((CstType) other).type.getDescriptor(); + return thisDescriptor.compareTo(otherDescriptor); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return "type{" + toHuman() + '}'; + } + + /** {@inheritDoc} */ + public Type getType() { + return Type.CLASS; + } + + /** {@inheritDoc} */ + @Override + public String typeName() { + return "type"; + } + + /** {@inheritDoc} */ + @Override + public boolean isCategory2() { + return false; + } + + /** {@inheritDoc} */ + public String toHuman() { + return type.toHuman(); + } + + /** + * Gets the underlying type (as opposed to the type corresponding + * to this instance as a constant, which is always + * {@code Class}). + * + * @return {@code non-null;} the type corresponding to the name + */ + public Type getClassType() { + return type; + } + + /** + * Gets the type descriptor for this instance. + * + * @return {@code non-null;} the descriptor + */ + public CstString getDescriptor() { + if (descriptor == null) { + descriptor = new CstString(type.getDescriptor()); + } + + return descriptor; + } +} diff --git a/dx/src/com/android/dx/rop/cst/StdConstantPool.java b/dx/src/com/android/dx/rop/cst/StdConstantPool.java new file mode 100644 index 0000000..244395d --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/StdConstantPool.java @@ -0,0 +1,139 @@ +/* + * 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.rop.cst; + +import com.android.dx.util.ExceptionWithContext; +import com.android.dx.util.Hex; +import com.android.dx.util.MutabilityControl; + +/** + * Standard implementation of {@link ConstantPool}, which directly stores + * an array of {@link Constant} objects and can be made immutable. + */ +public final class StdConstantPool + extends MutabilityControl implements ConstantPool { + /** {@code non-null;} array of entries */ + private final Constant[] entries; + + /** + * Constructs an instance. All indices initially contain {@code null}. + * + * @param size the size of the pool; this corresponds to the + * class file field {@code constant_pool_count}, and is in fact + * always at least one more than the actual size of the constant pool, + * as element {@code 0} is always invalid. + */ + public StdConstantPool(int size) { + super(size > 1); + + if (size < 1) { + throw new IllegalArgumentException("size < 1"); + } + + entries = new Constant[size]; + } + + /** {@inheritDoc} */ + public int size() { + return entries.length; + } + + /** {@inheritDoc} */ + public Constant getOrNull(int n) { + try { + return entries[n]; + } catch (IndexOutOfBoundsException ex) { + // Translate the exception. + return throwInvalid(n); + } + } + + /** {@inheritDoc} */ + public Constant get0Ok(int n) { + if (n == 0) { + return null; + } + + return get(n); + } + + /** {@inheritDoc} */ + public Constant get(int n) { + try { + Constant result = entries[n]; + + if (result == null) { + throwInvalid(n); + } + + return result; + } catch (IndexOutOfBoundsException ex) { + // Translate the exception. + return throwInvalid(n); + } + } + + /** + * Sets the entry at the given index. + * + * @param n {@code >= 1, < size();} which entry + * @param cst {@code null-ok;} the constant to store + */ + public void set(int n, Constant cst) { + throwIfImmutable(); + + boolean cat2 = (cst != null) && cst.isCategory2(); + + if (n < 1) { + throw new IllegalArgumentException("n < 1"); + } + + if (cat2) { + // Storing a category-2 entry nulls out the next index. + if (n == (entries.length - 1)) { + throw new IllegalArgumentException("(n == size - 1) && " + + "cst.isCategory2()"); + } + entries[n + 1] = null; + } + + if ((cst != null) && (entries[n] == null)) { + /* + * Overwriting the second half of a category-2 entry nulls out + * the first half. + */ + Constant prev = entries[n - 1]; + if ((prev != null) && prev.isCategory2()) { + entries[n - 1] = null; + } + } + + entries[n] = cst; + } + + /** + * Throws the right exception for an invalid cpi. + * + * @param idx the bad cpi + * @return never + * @throws ExceptionWithContext always thrown + */ + private static Constant throwInvalid(int idx) { + throw new ExceptionWithContext("invalid constant pool index " + + Hex.u2(idx)); + } +} diff --git a/dx/src/com/android/dx/rop/cst/TypedConstant.java b/dx/src/com/android/dx/rop/cst/TypedConstant.java new file mode 100644 index 0000000..1c738ee --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/TypedConstant.java @@ -0,0 +1,49 @@ +/* + * 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.rop.cst; + +import com.android.dx.rop.type.TypeBearer; + +/** + * Base class for constants which implement {@link TypeBearer}. + */ +public abstract class TypedConstant + extends Constant implements TypeBearer { + /** + * {@inheritDoc} + * + * This implementation always returns {@code this}. + */ + public final TypeBearer getFrameType() { + return this; + } + + /** {@inheritDoc} */ + public final int getBasicType() { + return getType().getBasicType(); + } + + /** {@inheritDoc} */ + public final int getBasicFrameType() { + return getType().getBasicFrameType(); + } + + /** {@inheritDoc} */ + public final boolean isConstant() { + return true; + } +} diff --git a/dx/src/com/android/dx/rop/cst/Zeroes.java b/dx/src/com/android/dx/rop/cst/Zeroes.java new file mode 100644 index 0000000..7250b5a --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/Zeroes.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 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.rop.cst; + +import com.android.dx.rop.type.Type; + +/** + * Utility for turning types into zeroes. + */ +public final class Zeroes { + /** + * This class is uninstantiable. + */ + private Zeroes() { + // This space intentionally left blank. + } + + /** + * Gets the "zero" (or {@code null}) value for the given type. + * + * @param type {@code non-null;} the type in question + * @return {@code non-null;} its "zero" value + */ + public static Constant zeroFor(Type type) { + switch (type.getBasicType()) { + case Type.BT_BOOLEAN: return CstBoolean.VALUE_FALSE; + case Type.BT_BYTE: return CstByte.VALUE_0; + case Type.BT_CHAR: return CstChar.VALUE_0; + case Type.BT_DOUBLE: return CstDouble.VALUE_0; + case Type.BT_FLOAT: return CstFloat.VALUE_0; + case Type.BT_INT: return CstInteger.VALUE_0; + case Type.BT_LONG: return CstLong.VALUE_0; + case Type.BT_SHORT: return CstShort.VALUE_0; + case Type.BT_OBJECT: return CstKnownNull.THE_ONE; + default: { + throw new UnsupportedOperationException("no zero for type: " + + type.toHuman()); + } + } + } +} diff --git a/dx/src/com/android/dx/rop/cst/package.html b/dx/src/com/android/dx/rop/cst/package.html new file mode 100644 index 0000000..c784d16 --- /dev/null +++ b/dx/src/com/android/dx/rop/cst/package.html @@ -0,0 +1,9 @@ +<body> +<p>Interfaces and implementation of things related to the constant pool.</p> + +<p><b>PACKAGES USED:</b> +<ul> +<li><code>com.android.dx.rop.type</code></li> +<li><code>com.android.dx.util</code></li> +</ul> +</body> |