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:
018: package org.apache.harmony.luni.internal.reflect;
019:
020: import java.lang.reflect.Constructor;
021: import java.lang.reflect.Field;
022: import java.lang.reflect.Method;
023:
024: class ProxyConstantPool implements ProxyConstants {
025: public static final int UTF8_INITIAL_SIZE = 50;
026:
027: public static final int STRING_INITIAL_SIZE = 21;
028:
029: public static final int FIELD_INITIAL_SIZE = 7;
030:
031: public static final int METHOD_INITIAL_SIZE = 21;
032:
033: public static final int INTERFACE_INITIAL_SIZE = 21;
034:
035: public static final int CLASS_INITIAL_SIZE = 21;
036:
037: public static final int NAMEANDTYPE_INITIAL_SIZE = 21;
038:
039: public static final int CONSTANTPOOL_INITIAL_SIZE = 500;
040:
041: public static final int CONSTANTPOOL_GROW_SIZE = 1000;
042:
043: ProxyCharArrayCache UTF8Cache;
044:
045: ProxyCharArrayCache stringCache;
046:
047: ProxyCharArrayCache classNameCache;
048:
049: ProxyObjectCache fieldCache;
050:
051: ProxyObjectCache methodCache;
052:
053: ProxyObjectCache interfaceMethodCache;
054:
055: ProxyNameAndTypeCache nameAndTypeCache;
056:
057: byte[] poolContent;
058:
059: int currentIndex;
060:
061: int currentOffset;
062:
063: ProxyConstantPool(ProxyClassFile classFile) {
064: UTF8Cache = new ProxyCharArrayCache(UTF8_INITIAL_SIZE);
065: stringCache = new ProxyCharArrayCache(STRING_INITIAL_SIZE);
066: classNameCache = new ProxyCharArrayCache(CLASS_INITIAL_SIZE);
067: fieldCache = new ProxyObjectCache(FIELD_INITIAL_SIZE);
068: methodCache = new ProxyObjectCache(METHOD_INITIAL_SIZE);
069: interfaceMethodCache = new ProxyObjectCache(
070: INTERFACE_INITIAL_SIZE);
071: nameAndTypeCache = new ProxyNameAndTypeCache(
072: NAMEANDTYPE_INITIAL_SIZE);
073: poolContent = classFile.header;
074: currentOffset = classFile.headerOffset;
075: currentIndex = 1;
076: }
077:
078: int literalIndex(char[] utf8Constant) {
079: int index;
080: if ((index = UTF8Cache.get(utf8Constant)) < 0) {
081: writeU1(Utf8Tag);
082: int savedCurrentOffset = currentOffset;
083: if (currentOffset + 2 >= poolContent.length) {
084: int length = poolContent.length;
085: System.arraycopy(poolContent, 0,
086: (poolContent = new byte[length
087: + CONSTANTPOOL_GROW_SIZE]), 0, length);
088: }
089: currentOffset += 2;
090: int length = 0;
091: for (int i = 0; i < utf8Constant.length; i++) {
092: char current = utf8Constant[i];
093: if ((current >= 0x0001) && (current <= 0x007F)) {
094: // we only need one byte: ASCII table
095: writeU1(current);
096: length++;
097: } else if (current > 0x07FF) {
098: // we need 3 bytes
099: length += 3;
100: writeU1(0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110
101: // 0000
102: writeU1(0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000
103: // 0000
104: writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000
105: } else {
106: // we can be 0 or between 0x0080 and 0x07FF
107: // In that case we only need 2 bytes
108: length += 2;
109: writeU1(0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100
110: // 0000
111: writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000
112: }
113: }
114: if (length >= 65535) {
115: currentOffset = savedCurrentOffset - 1;
116: return -1;
117: }
118: index = UTF8Cache.put(utf8Constant, currentIndex++);
119: // Now we know the length that we have to write in the constant pool
120: // we use savedCurrentOffset to do that
121: poolContent[savedCurrentOffset] = (byte) (length >> 8);
122: poolContent[savedCurrentOffset + 1] = (byte) length;
123: }
124: return index;
125: }
126:
127: int literalIndex(Field aField) {
128: return literalIndex(aField.getDeclaringClass().getName(),
129: aField.getName(), aField.getType());
130: }
131:
132: int literalIndex(String declaringClass, String name, Class clazz) {
133: int index;
134: String key = declaringClass + "." + name;
135: if ((index = fieldCache.get(key)) < 0) {
136: int classIndex = typeIndex(declaringClass);
137: int nameAndTypeIndex = literalIndexForNameAndType(
138: literalIndex(name.toCharArray()),
139: literalIndex(ProxyClassFile
140: .getConstantPoolName(clazz)));
141: index = fieldCache.put(key, currentIndex++);
142: writeU1(FieldRefTag);
143: writeU2(classIndex);
144: writeU2(nameAndTypeIndex);
145: }
146: return index;
147: }
148:
149: int literalIndex(Constructor<?> aMethod) {
150: int index;
151: if ((index = methodCache.get(aMethod)) < 0) {
152: int classIndex = typeIndex(aMethod.getDeclaringClass()
153: .getName());
154: int nameAndTypeIndex = literalIndexForNameAndType(
155: literalIndex(Init), literalIndex(ProxyClassFile
156: .getConstantPoolName(aMethod)));
157: index = methodCache.put(aMethod, currentIndex++);
158: writeU1(MethodRefTag);
159: writeU2(classIndex);
160: writeU2(nameAndTypeIndex);
161: }
162: return index;
163: }
164:
165: int literalIndex(Method aMethod) {
166: int index;
167: if (aMethod.getDeclaringClass().isInterface()) {
168: if ((index = interfaceMethodCache.get(aMethod)) < 0) {
169: int classIndex = typeIndex(aMethod.getDeclaringClass()
170: .getName());
171: int nameAndTypeIndex = literalIndexForNameAndType(
172: literalIndex(aMethod.getName().toCharArray()),
173: literalIndex(ProxyClassFile
174: .getConstantPoolName(aMethod)));
175: index = interfaceMethodCache.put(aMethod,
176: currentIndex++);
177: writeU1(InterfaceMethodRefTag);
178: writeU2(classIndex);
179: writeU2(nameAndTypeIndex);
180: }
181: } else if ((index = methodCache.get(aMethod)) < 0) {
182: int classIndex = typeIndex(aMethod.getDeclaringClass()
183: .getName());
184: int nameAndTypeIndex = literalIndexForNameAndType(
185: literalIndex(aMethod.getName().toCharArray()),
186: literalIndex(ProxyClassFile
187: .getConstantPoolName(aMethod)));
188: index = methodCache.put(aMethod, currentIndex++);
189: writeU1(MethodRefTag);
190: writeU2(classIndex);
191: writeU2(nameAndTypeIndex);
192: }
193: return index;
194: }
195:
196: int literalIndex(String stringConstant) {
197: int index;
198: char[] stringCharArray = stringConstant.toCharArray();
199: if ((index = stringCache.get(stringCharArray)) < 0) {
200: int stringIndex = literalIndex(stringCharArray);
201: index = stringCache.put(stringCharArray, currentIndex++);
202: writeU1(StringTag);
203: writeU2(stringIndex);
204: }
205: return index;
206: }
207:
208: int literalIndexForLdc(char[] stringCharArray) {
209: int index;
210: if ((index = stringCache.get(stringCharArray)) < 0) {
211: int stringIndex;
212: if ((stringIndex = UTF8Cache.get(stringCharArray)) < 0) {
213: writeU1(Utf8Tag);
214: int savedCurrentOffset = currentOffset;
215: if (currentOffset + 2 >= poolContent.length) {
216: int length = poolContent.length;
217: System.arraycopy(poolContent, 0,
218: (poolContent = new byte[length
219: + CONSTANTPOOL_GROW_SIZE]), 0,
220: length);
221: }
222: currentOffset += 2;
223: int length = 0;
224: for (int i = 0; i < stringCharArray.length; i++) {
225: char current = stringCharArray[i];
226: if ((current >= 0x0001) && (current <= 0x007F)) {
227: // we only need one byte: ASCII table
228: writeU1(current);
229: length++;
230: } else if (current > 0x07FF) {
231: // we need 3 bytes
232: length += 3;
233: writeU1(0xE0 | ((current >> 12) & 0x0F)); // 0xE0 =
234: // 1110 0000
235: writeU1(0x80 | ((current >> 6) & 0x3F)); // 0x80 =
236: // 1000 0000
237: writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000
238: } else {
239: // we can be 0 or between 0x0080 and 0x07FF
240: // In that case we only need 2 bytes
241: length += 2;
242: writeU1(0xC0 | ((current >> 6) & 0x1F)); // 0xC0 =
243: // 1100 0000
244: writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000
245: }
246: }
247: if (length >= 65535) {
248: currentOffset = savedCurrentOffset - 1;
249: return -1;
250: }
251: stringIndex = UTF8Cache.put(stringCharArray,
252: currentIndex++);
253: // Now we know the length that we have to write in the constant
254: // pool
255: // we use savedCurrentOffset to do that
256: if (length > 65535)
257: return 0;
258: poolContent[savedCurrentOffset] = (byte) (length >> 8);
259: poolContent[savedCurrentOffset + 1] = (byte) length;
260: }
261: index = stringCache.put(stringCharArray, currentIndex++);
262: writeU1(StringTag);
263: writeU2(stringIndex);
264: }
265: return index;
266: }
267:
268: int literalIndexForNameAndType(int nameIndex, int typeIndex) {
269: int index;
270: int[] key = new int[] { nameIndex, typeIndex };
271: if ((index = nameAndTypeCache.get(key)) == -1) {
272: index = nameAndTypeCache.put(key, currentIndex++);
273: writeU1(NameAndTypeTag);
274: writeU2(nameIndex);
275: writeU2(typeIndex);
276: }
277: return index;
278: }
279:
280: int typeIndex(String typeName) {
281: int index;
282: if (typeName.indexOf('.') != -1)
283: typeName = typeName.replace('.', '/');
284: char[] charArray = typeName.toCharArray();
285: if ((index = classNameCache.get(charArray)) < 0) {
286: int nameIndex = literalIndex(charArray);
287: index = classNameCache.put(charArray, currentIndex++);
288: writeU1(ClassTag);
289: writeU2(nameIndex);
290: }
291: return index;
292: }
293:
294: private final void writeU1(int value) {
295: try {
296: poolContent[currentOffset++] = (byte) value;
297: } catch (IndexOutOfBoundsException e) {
298: // currentOffset has been ++ already (see the -1)
299: int length = poolContent.length;
300: System.arraycopy(poolContent, 0,
301: (poolContent = new byte[length
302: + CONSTANTPOOL_GROW_SIZE]), 0, length);
303: poolContent[currentOffset - 1] = (byte) value;
304: }
305: }
306:
307: private final void writeU2(int value) {
308: try {
309: poolContent[currentOffset++] = (byte) (value >> 8);
310: } catch (IndexOutOfBoundsException e) {
311: // currentOffset has been ++ already (see the -1)
312: int length = poolContent.length;
313: System.arraycopy(poolContent, 0,
314: (poolContent = new byte[length
315: + CONSTANTPOOL_GROW_SIZE]), 0, length);
316: poolContent[currentOffset - 1] = (byte) (value >> 8);
317: }
318: try {
319: poolContent[currentOffset++] = (byte) value;
320: } catch (IndexOutOfBoundsException e) {
321: // currentOffset has been ++ already (see the -1)
322: int length = poolContent.length;
323: System.arraycopy(poolContent, 0,
324: (poolContent = new byte[length
325: + CONSTANTPOOL_GROW_SIZE]), 0, length);
326: poolContent[currentOffset - 1] = (byte) value;
327: }
328: }
329: }
|