001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.harmony.pack200;
018:
019: import java.util.ArrayList;
020:
021: import org.apache.harmony.pack200.bytecode.CPClass;
022: import org.apache.harmony.pack200.bytecode.CPDouble;
023: import org.apache.harmony.pack200.bytecode.CPFieldRef;
024: import org.apache.harmony.pack200.bytecode.CPFloat;
025: import org.apache.harmony.pack200.bytecode.CPInteger;
026: import org.apache.harmony.pack200.bytecode.CPInterfaceMethodRef;
027: import org.apache.harmony.pack200.bytecode.CPLong;
028: import org.apache.harmony.pack200.bytecode.CPMethodRef;
029: import org.apache.harmony.pack200.bytecode.CPString;
030: import org.apache.harmony.pack200.bytecode.CPUTF8;
031: import org.apache.harmony.pack200.bytecode.ClassConstantPool;
032: import org.apache.harmony.pack200.bytecode.ConstantPoolEntry;
033:
034: public class SegmentConstantPool {
035: /**
036: *
037: */
038: private CpBands bands;
039:
040: /**
041: * @param bands
042: */
043: public SegmentConstantPool(CpBands bands) {
044: this .bands = bands;
045: }
046:
047: // define in archive order
048:
049: public static final int ALL = 0;
050: public static final int UTF_8 = 1;
051: public static final int CP_INT = 2;
052: public static final int CP_FLOAT = 3;
053: public static final int CP_LONG = 4;
054: public static final int CP_DOUBLE = 5;
055: public static final int CP_STRING = 6;
056: public static final int CP_CLASS = 7;
057: public static final int SIGNATURE = 8; // TODO and more to come --
058: public static final int CP_DESCR = 9;
059: public static final int CP_FIELD = 10;
060: public static final int CP_METHOD = 11;
061: public static final int CP_IMETHOD = 12;
062:
063: public Object getValue(int cp, long value) throws Pack200Exception {
064: int index = (int) value;
065: if (index == -1) {
066: return null;
067: } else if (index < 0) {
068: throw new Pack200Exception("Cannot have a negative range");
069: } else if (cp == UTF_8) {
070: return bands.getCpUTF8()[index];
071: } else if (cp == CP_INT) {
072: return new Integer(bands.getCpInt()[index]);
073: } else if (cp == CP_FLOAT) {
074: return new Float(bands.getCpFloat()[index]);
075: } else if (cp == CP_LONG) {
076: return new Long(bands.getCpLong()[index]);
077: } else if (cp == CP_DOUBLE) {
078: return new Double(bands.getCpDouble()[index]);
079: } else if (cp == CP_STRING) {
080: return bands.getCpString()[index];
081: } else if (cp == CP_CLASS) {
082: return bands.getCpClass()[index];
083: } else if (cp == SIGNATURE) {
084: return bands.getCpSignature()[index];
085: } else if (cp == CP_DESCR) {
086: return bands.getCpDescriptor()[index];
087: } else {
088: // etc
089: throw new Error("Get value incomplete");
090: }
091: }
092:
093: /**
094: * Subset the constant pool of the specified type
095: * to be just that which has the specified class
096: * name. Answer the ConstantPoolEntry at the
097: * desiredIndex of the subsetted pool.
098: *
099: * @param cp type of constant pool array to search
100: * @param desiredIndex index of the constant pool
101: * @param desiredClassName class to use to generate a
102: * subset of the pool
103: * @return ConstantPoolEntry
104: * @throws Pack200Exception
105: */
106: public ConstantPoolEntry getClassSpecificPoolEntry(int cp,
107: long desiredIndex, String desiredClassName)
108: throws Pack200Exception {
109: int index = (int) desiredIndex;
110: int realIndex = -1;
111: String array[] = null;
112: if (cp == CP_FIELD) {
113: array = bands.getCpFieldClass();
114: } else if (cp == CP_METHOD) {
115: array = bands.getCpMethodClass();
116: } else if (cp == CP_IMETHOD) {
117: array = bands.getCpIMethodClass();
118: } else {
119: throw new Error("Don't know how to handle " + cp);
120: }
121: realIndex = matchSpecificPoolEntryIndex(array,
122: desiredClassName, index);
123: return getConstantPoolEntry(cp, realIndex);
124: }
125:
126: /**
127: * Given the name of a class, answer the CPClass associated
128: * with that class. Answer null if the class doesn't exist.
129: * @param name Class name to look for (form: java/lang/Object)
130: * @return CPClass for that class name, or null if not found.
131: */
132: public ConstantPoolEntry getClassPoolEntry(String name) {
133: String classes[] = bands.getCpClass();
134: int index = matchSpecificPoolEntryIndex(classes, name, 0);
135: if (index == -1) {
136: return null;
137: }
138: try {
139: return getConstantPoolEntry(CP_CLASS, index);
140: } catch (Pack200Exception ex) {
141: throw new Error("Error getting class pool entry");
142: }
143: }
144:
145: /**
146: * Answer the init method for the specified class.
147: * @param cp constant pool to search (must be CP_METHOD)
148: * @param value index of init method
149: * @param desiredClassName String class name of the init method
150: * @return CPMethod init method
151: * @throws Pack200Exception
152: */
153: public ConstantPoolEntry getInitMethodPoolEntry(int cp, long value,
154: String desiredClassName) throws Pack200Exception {
155: int realIndex = -1;
156: String desiredRegex = "^<init>.*";
157: if (cp == CP_METHOD) {
158: realIndex = matchSpecificPoolEntryIndex(bands
159: .getCpMethodClass(), bands.getCpMethodDescriptor(),
160: desiredClassName, desiredRegex, (int) value);
161: } else {
162: throw new Error("Nothing but CP_METHOD can be an <init>");
163: }
164: return getConstantPoolEntry(cp, realIndex);
165: }
166:
167: /**
168: * A number of things make use of subsets of structures.
169: * In one particular example, _super bytecodes will use a subset
170: * of method or field classes which have just those methods /
171: * fields defined in the superclass. Similarly, _this bytecodes
172: * use just those methods/fields defined in this class, and _init
173: * bytecodes use just those methods that start with <init>.
174: *
175: * This method takes an array of names, a String to match for,
176: * an index and a boolean as parameters, and answers the array
177: * position in the array of the indexth element which matches
178: * (or equals) the String (depending on the state of the boolean)
179: *
180: * In other words, if the class array consists of:
181: * Object [position 0, 0th instance of Object]
182: * String [position 1, 0th instance of String]
183: * String [position 2, 1st instance of String]
184: * Object [position 3, 1st instance of Object]
185: * Object [position 4, 2nd instance of Object]
186: * then matchSpecificPoolEntryIndex(..., "Object", 2, false) will
187: * answer 4. matchSpecificPoolEntryIndex(..., "String", 0, false)
188: * will answer 1.
189: *
190: * @param nameArray Array of Strings against which the compareString is tested
191: * @param compareString String for which to search
192: * @param desiredIndex nth element with that match (counting from 0)
193: * @return int index into nameArray, or -1 if not found.
194: */
195: protected int matchSpecificPoolEntryIndex(String[] nameArray,
196: String compareString, int desiredIndex) {
197: return matchSpecificPoolEntryIndex(nameArray, nameArray,
198: compareString, ".*", desiredIndex);
199: }
200:
201: /**
202: * This method's function is to look through pairs of arrays.
203: * It keeps track of the number of hits it finds using the
204: * following basis of comparison for a hit:
205: * - the primaryArray[index] must be .equals() to the primaryCompareString
206: * - the secondaryArray[index] .matches() the secondaryCompareString
207: * When the desiredIndex number of hits has been reached, the index
208: * into the original two arrays of the element hit is returned.
209: *
210: * @param primaryArray The first array to search
211: * @param secondaryArray The second array (must be same .length as primaryArray)
212: * @param primaryCompareString The String to compare against primaryArray using .equals()
213: * @param secondaryCompareRegex The String to compare against secondaryArray using .matches()
214: * @param desiredIndex The nth hit whose position we're seeking
215: * @return int index that represents the position of the nth hit in primaryArray and secondaryArray
216: */
217: protected int matchSpecificPoolEntryIndex(String[] primaryArray,
218: String[] secondaryArray, String primaryCompareString,
219: String secondaryCompareRegex, int desiredIndex) {
220: int instanceCount = -1;
221: for (int index = 0; index < primaryArray.length; index++) {
222: if ((primaryArray[index].equals(primaryCompareString))
223: && secondaryArray[index]
224: .matches(secondaryCompareRegex)) {
225: instanceCount++;
226: if (instanceCount == desiredIndex) {
227: return index;
228: }
229: }
230: }
231: // We didn't return in the for loop, so the desiredMatch
232: // with desiredIndex must not exist in the array.
233: return -1;
234: }
235:
236: public ConstantPoolEntry getConstantPoolEntry(int cp, long value)
237: throws Pack200Exception {
238: int index = (int) value;
239: if (index == -1) {
240: return null;
241: } else if (index < 0) {
242: throw new Pack200Exception("Cannot have a negative range");
243: } else if (cp == UTF_8) {
244: return new CPUTF8(bands.getCpUTF8()[index],
245: ClassConstantPool.DOMAIN_NORMALASCIIZ);
246: } else if (cp == CP_INT) {
247: return new CPInteger(new Integer(bands.getCpInt()[index]));
248: } else if (cp == CP_FLOAT) {
249: return new CPFloat(new Float(bands.getCpFloat()[index]));
250: } else if (cp == CP_LONG) {
251: return new CPLong(new Long(bands.getCpLong()[index]));
252: } else if (cp == CP_DOUBLE) {
253: return new CPDouble(new Double(bands.getCpDouble()[index]));
254: } else if (cp == CP_STRING) {
255: return new CPString(bands.getCpString()[index]);
256: } else if (cp == CP_CLASS) {
257: return new CPClass(bands.getCpClass()[index]);
258: } else if (cp == SIGNATURE) {
259: throw new Error(
260: "I don't know what to do with signatures yet");
261: // return null /* new CPSignature(bands.getCpSignature()[index]) */;
262: } else if (cp == CP_DESCR) {
263: throw new Error(
264: "I don't know what to do with descriptors yet");
265: // return null /* new CPDescriptor(bands.getCpDescriptor()[index]) */;
266: } else if (cp == CP_FIELD) {
267: return new CPFieldRef(bands.getCpFieldClass()[index], bands
268: .getCpFieldDescriptor()[index]);
269: } else if (cp == CP_METHOD) {
270: return new CPMethodRef(bands.getCpMethodClass()[index],
271: bands.getCpMethodDescriptor()[index]);
272: } else if (cp == CP_IMETHOD) {
273: return new CPInterfaceMethodRef(
274: bands.getCpIMethodClass()[index], bands
275: .getCpIMethodDescriptor()[index]);
276: } else {
277: // etc
278: throw new Error("Get value incomplete");
279: }
280: }
281:
282: public ConstantPoolEntry[] getCpAll() throws Pack200Exception {
283: ArrayList cpAll = new ArrayList();
284: // TODO: this is 1.5-specific. Try to get rid
285: // of it.
286: for (int index = 0; index < bands.getCpUTF8().length; index++) {
287: cpAll.add(getConstantPoolEntry(UTF_8, index));
288: }
289: for (int index = 0; index < bands.getCpInt().length; index++) {
290: cpAll.add(getConstantPoolEntry(CP_INT, index));
291: }
292: for (int index = 0; index < bands.getCpFloat().length; index++) {
293: cpAll.add(getConstantPoolEntry(CP_FLOAT, index));
294: }
295: for (int index = 0; index < bands.getCpLong().length; index++) {
296: cpAll.add(getConstantPoolEntry(CP_LONG, index));
297: }
298: for (int index = 0; index < bands.getCpDouble().length; index++) {
299: cpAll.add(getConstantPoolEntry(CP_DOUBLE, index));
300: }
301: for (int index = 0; index < bands.getCpString().length; index++) {
302: cpAll.add(getConstantPoolEntry(CP_STRING, index));
303: }
304: for (int index = 0; index < bands.getCpClass().length; index++) {
305: cpAll.add(getConstantPoolEntry(CP_CLASS, index));
306: }
307: for (int index = 0; index < bands.getCpFieldClass().length; index++) {
308: cpAll.add(getConstantPoolEntry(CP_FIELD, index));
309: }
310: for (int index = 0; index < bands.getCpMethodClass().length; index++) {
311: cpAll.add(getConstantPoolEntry(CP_METHOD, index));
312: }
313: for (int index = 0; index < bands.getCpIMethodClass().length; index++) {
314: cpAll.add(getConstantPoolEntry(CP_IMETHOD, index));
315: }
316:
317: ConstantPoolEntry[] result = new ConstantPoolEntry[cpAll.size()];
318: cpAll.toArray(result);
319: return result;
320: }
321:
322: }
|